home *** CD-ROM | disk | FTP | other *** search
/ ETO Development Tools 1 / ETO Development Tools 1.iso / Tools - Objects / MacApp / MacApp 2.0 CD Release / MacApp 2.0 (Many Libraries) / Examples / Calc / UCalc.inc1.p < prev    next >
Encoding:
Text File  |  1990-03-27  |  134.7 KB  |  5,204 lines  |  [TEXT/MPS ]

  1. {$P}
  2. {[a-,body+,h-,o=100,r+,rec+,t=4,u+,#+,j=20/57/1$,n-]}
  3. { UCalc.inc1.p}
  4. { Copyright © 1985 - 1990 by Apple Computer, Inc. All rights reserved. }
  5.  
  6. CONST
  7.     kTextScrapType        = 'TEXT';
  8.     kCalcScrapType        = 'CALC';
  9.  
  10.     kCellWidth            = 80;                            { default width of each cell }
  11.     kCellHeight         = 17;                            { default height of each cell }
  12.     kCellHBorder        = 2;                            { pixels separating cell contents from
  13.                                                          left/right edge }
  14.  
  15.     kCellFont            = applFont;
  16.     kCellFontSize        = 10;
  17.     kRowTitleWidth        = 32;                            { width of row titles }
  18.     kColumnTitleHeight    = 20;                            { height of column titles }
  19.     kTitlesFont         = applFont;                     { font for column/row titles }
  20.     kTitlesFontSize     = 10;                            { font size for column/row titles }
  21.  
  22.     kEntryFont            = applFont;                     { default font of cell contents }
  23.     kEntryFontSize        = 10;                            { default font size of cell contents }
  24.     kEntryHeight        = 20;                            { height of the cell entry view }
  25.  
  26.     kCalcMode            = Automatic;                    { default calculation mode }
  27.     kForceAutomatic     = TRUE;                         { force automatic calculation }
  28.     kSetDependents        = TRUE;                         { set cell's dependents }
  29.  
  30.     kDefaultJustification = TEJustCenter;                { default cell justification }
  31.     kNoJustification    = 2;                            { constant representing no justification }
  32.  
  33.     kValuePrecision     = 18;                            { digits of precision in our values }
  34.     kTELength            = (80 * 5);                     { number of characters in the text edit
  35.                                                          field }
  36.  
  37.     { Command Constants }
  38.  
  39.     cPrintSelection     = 180;
  40.     cRecalculate        = 401;
  41.     cAutoCalc            = 403;
  42.     cManualCalc         = 404;
  43.     cGeneral            = 501;
  44.     cNoDecimal            = 503;
  45.     cDecimal            = 504;
  46.     cScientific         = 505;
  47.     cSystemJustify        = 506;
  48.     cForceLeftJustify    = 507;
  49.     cRightJustify        = 508;
  50.     cCenter             = 509;
  51.     cSelection            = 1000;
  52.     cSizeColumn         = 1001;
  53.     cCutText            = 1103;
  54.     cCopyText            = 1104;
  55.     cClearText            = 1106;
  56.     cCutCells            = 1203;
  57.     cCopyCells            = 1204;
  58.     cClearCells         = 1206;
  59.     cStandardCut        = 1303;
  60.     cStandardCopy        = 1304;
  61.     cStandardClear        = 1306;
  62.  
  63.     { Cursor Resource ID's }
  64.  
  65.     kColumnSizingCursor = 256;                            { cursor for resizing a column }
  66.     kRowSizingCursor    = 257;                            { cursor for resizing a row--UNUSED }
  67.  
  68. TYPE
  69.     TypeOfLine            = (NoLine,                        { for DrawLine routine}
  70.                            SolidLine, BoldLine, VDottedLine, HDottedLine, RowSeparator,
  71.                            ColumnSeparator);
  72.  
  73. VAR
  74.     gGeneralFormat:     ValueFormat;                    { SANE conversion formats }
  75.     gDecimalFormat:     ValueFormat;
  76.     gNoDecimalFormat:    ValueFormat;
  77.     gScientificFormat:    ValueFormat;
  78.     gNoFormat:            ValueFormat;
  79.     gDefaultFormat:     FormatRecord;                    { default cell format }
  80.  
  81.     gColumnSeparatorPattern: Pattern;                    { patterns for separator lines }
  82.     gRowSeparatorPattern: Pattern;
  83.  
  84. {--------------------------------------------------------------------------------------------------}
  85.     {$S AFields}
  86.  
  87. PROCEDURE FormatFields(aTitle: Str255;
  88.                        VAR aFormat: FormatRecord;
  89.                        PROCEDURE DoToField(fieldName: Str255;
  90.                                            fieldAddr: Ptr;
  91.                                            fieldType: INTEGER));
  92.  
  93.     VAR
  94.         aString:            Str255;
  95.         anInteger:            INTEGER;
  96.         aStyle:             Style;
  97.  
  98.     BEGIN
  99.     { Because our brain-damaged compiler won't allow you to pass the address of byte-aligned
  100.       fields in packed records, we have to move the fields of a FormatRecord into a temporary
  101.       variable, then pass the address of the temporary. }
  102.  
  103.     DoToField(aTitle, NIL, bTitle);
  104.     WITH aFormat DO
  105.         BEGIN
  106.         CASE aFormat.fStyle OF
  107.             NoStyle:
  108.                 aString := 'NoStyle';
  109.             General:
  110.                 aString := 'General';
  111.             DecimalStyle:
  112.                 aString := 'DecimalStyle';
  113.             NoDecimal:
  114.                 aString := 'NoDecimal';
  115.             Scientific:
  116.                 aString := 'Scientific';
  117.             OTHERWISE
  118.                 aString := 'UnknownStyle';
  119.         END;
  120.         DoToField('  fStyle', @aString, bString);
  121.  
  122.         anInteger := fDigits;
  123.         DoToField('  fDigits', @anInteger, bInteger);
  124.  
  125.         CASE fJustification OF
  126.             teJustSystem:
  127.                 aString := 'System';
  128.             teForceLeft:
  129.                 aString := 'Forced Left';
  130.             TEJustCenter:
  131.                 aString := 'Center';
  132.             TEJustRight:
  133.                 aString := 'Right';
  134.             kNoJustification:
  135.                 aString := 'None';
  136.             OTHERWISE
  137.                 aString := 'Unknown';
  138.         END;
  139.         DoToField('  fJustification', @aString, bString);
  140.  
  141.         anInteger := fFontNumber;
  142.         DoToField('  fFontNumber', @anInteger, bFontName);
  143.         anInteger := fFontSize;
  144.         DoToField('  fFontSize', @anInteger, bInteger);
  145.         aStyle := fFontStyle;
  146.         DoToField('  fFontStyle', @aStyle, bStyle);
  147.         END;
  148.     END;
  149.  
  150. {--------------------------------------------------------------------------------------------------}
  151. {$S AReadFile}
  152.  
  153. PROCEDURE ReadCellCoordinate(theRefNum: INTEGER;
  154.                              VAR r: RowNumber;
  155.                              VAR c: ColumnNumber);
  156. { Reads a cell coordinate from a file }
  157.  
  158.     VAR
  159.         cellCoordinate:     Point;
  160.  
  161.     BEGIN
  162.     ReadBytes(theRefNum, SIZEOF(cellCoordinate), @cellCoordinate);
  163.     r := cellCoordinate.v;
  164.     c := cellCoordinate.h;
  165.     END;
  166.  
  167. {***************************************************************************************************
  168.      T C a l c A p p l i c a t i o n
  169. ***************************************************************************************************}
  170. {$S AInit}
  171.  
  172. PROCEDURE TCalcApplication.ICalcApplication(itsFileType: OSType);
  173.  
  174.     BEGIN
  175.     IApplication(itsFileType);
  176.  
  177.     gGeneralFormat.Style := FloatDecimal;
  178.     gGeneralFormat.digits := kValuePrecision;
  179.  
  180.     gDecimalFormat.Style := FixedDecimal;
  181.     gDecimalFormat.digits := 2;
  182.  
  183.     gNoDecimalFormat.Style := FixedDecimal;
  184.     gNoDecimalFormat.digits := 0;
  185.  
  186.     gScientificFormat.Style := FloatDecimal;
  187.     gScientificFormat.digits := 2;
  188.  
  189.     gNoFormat.Style := FixedDecimal;
  190.     gNoFormat.digits := - 1;
  191.  
  192.     gDefaultFormat.fJustification := kDefaultJustification;
  193.     gDefaultFormat.fStyle := General;
  194.     gDefaultFormat.fDigits := 0;
  195.     gDefaultFormat.fFontNumber := kCellFont;
  196.     gDefaultFormat.fFontSize := kCellFontSize;
  197.     gDefaultFormat.fFontStyle := [];
  198.  
  199.     gColumnSeparatorPattern := gray;
  200.     gRowSeparatorPattern := gray;
  201.  
  202.     { Suppress Linker dead-stripping of these classes }
  203.     IF gDeadStripSuppression THEN
  204.         BEGIN
  205.         IF Member(TObject(NIL), TCalcWindow) THEN;
  206.         IF Member(TObject(NIL), TCellsView) THEN;
  207.         IF Member(TObject(NIL), TRowsView) THEN;
  208.         IF Member(TObject(NIL), TColumnsView) THEN;
  209.         IF Member(TObject(NIL), TEntryView) THEN;
  210.         IF Member(TObject(NIL), TCoordView) THEN;
  211.         END;
  212.     END;
  213.  
  214. {--------------------------------------------------------------------------------------------------}
  215. {$S ADoCommand}
  216.  
  217. PROCEDURE TCalcApplication.AboutToLoseControl(convertClipboard: BOOLEAN); OVERRIDE;
  218. { Remove Edit menu buzzwords for incoming Desk Accessory }
  219.  
  220.     BEGIN
  221.     SetEditCmdName(cCut, cStandardCut);
  222.     SetEditCmdName(cCopy, cStandardCopy);
  223.     SetEditCmdName(cClear, cStandardClear);
  224.  
  225.     INHERITED AboutToLoseControl(convertClipboard);
  226.     END;
  227.  
  228. {--------------------------------------------------------------------------------------------------}
  229. {$S AOpen}
  230.  
  231. FUNCTION TCalcApplication.DoMakeDocument(itsCmdNumber: cmdNumber): TDocument;
  232.  
  233.     VAR
  234.         aCalcDocument:        TCalcDocument;
  235.         dimensions:         Rect;
  236.  
  237.     BEGIN
  238.     { Allocate and initialize the document}
  239.     NEW(aCalcDocument);
  240.     FailNIL(aCalcDocument);
  241.     SetRect(dimensions, 1, 1, kMaxColumns, kMaxRows);
  242.     aCalcDocument.ICalcDocument(dimensions);
  243.     DoMakeDocument := aCalcDocument;
  244.     END;
  245.  
  246. {--------------------------------------------------------------------------------------------------}
  247. {$S AClipboard}
  248.  
  249. FUNCTION TCalcApplication.MakeViewForAlienClipboard: TView; OVERRIDE;
  250.  { Launch a view to represent the data found in the Clipboard at
  251.    application start-up time, or when returning from an excursion
  252.    to MultiFinder, or when returning from a Desk Accessory.  This
  253.    creates a clipboard for 'CALC' scrap. }
  254.  
  255.     VAR
  256.         calcScrap:            Handle;
  257.         scrapOffset:        LONGINT;
  258.         clipDocument:        TCalcDocument;
  259.         clipView:            TCellsView;
  260.         scrapInfo:            ScrapInfoRecord;
  261.         r:                    RowNumber;
  262.         c:                    ColumnNumber;
  263.         i:                    INTEGER;
  264.         cellsRead:            INTEGER;
  265.         cellCoord:            Point;
  266.         offset:             LONGINT;
  267.         aRow:                TRow;
  268.         aColumn:            TColumn;
  269.         aCell:                TCell;
  270.         perm:                BOOLEAN;
  271.         fi:                 FailInfo;
  272.  
  273. {--------------------------------------------------------------------------------------------------}
  274.  
  275.     PROCEDURE HdlScrapFailure(error: OSErr;
  276.                               message: LONGINT);
  277.  
  278.         BEGIN
  279.         calcScrap := DisposeIfHandle(calcScrap);
  280.  
  281.         FreeIfObject(clipDocument);
  282.         clipDocument := NIL;
  283.         END;
  284.  
  285.     BEGIN
  286.     { Before doing anything else, make sure the scrap contains my type }
  287.     IF GetScrap(NIL, kCalcScrapType, offset) > 0 THEN
  288.         BEGIN
  289.         clipDocument := NIL;                            { so failure handler knows to free it }
  290.         calcScrap := NIL;
  291.  
  292.         CatchFailures(fi, HdlScrapFailure);
  293.  
  294.         calcScrap := NewPermHandle(0);
  295.         FailNIL(calcScrap);
  296.  
  297.         perm := PermAllocation(TRUE);
  298.         scrapOffset := GetScrap(calcScrap, kCalcScrapType, offset);
  299.         perm := PermAllocation(perm);
  300.  
  301.     { Only a negative result indicates an error--FailOSErr considers any non-zero result an error. }
  302.         IF scrapOffset < 0 THEN
  303.             FailOSErr(scrapOffset);
  304.         scrapOffset := 0;
  305.  
  306.         ReadScrap(calcScrap, scrapOffset, @scrapInfo, SIZEOF(scrapInfo));
  307.         FailMemError;
  308.         NEW(clipDocument);
  309.         FailNIL(clipDocument);
  310.         clipDocument.ICalcDocument(scrapInfo.selection);
  311.         clipDocument.DoInitialState;
  312.  
  313.         NEW(clipView);
  314.         FailNIL(clipView);
  315.         clipView.ICellsView(clipDocument, TRUE, NIL);
  316.         clipDocument.fCellsView := clipView;
  317.  
  318.         FOR r := 1 TO clipDocument.fNoOfRows DO
  319.             BEGIN
  320.             NEW(aRow);
  321.             aRow.ReadFromScrap(calcScrap, scrapOffset);
  322.             clipDocument.AddRow(aRow);
  323.             END;
  324.  
  325.         FOR c := 1 TO clipDocument.fNoOfColumns DO
  326.             BEGIN
  327.             NEW(aColumn);
  328.             aColumn.ReadFromScrap(calcScrap, scrapOffset);
  329.             clipDocument.AddColumn(aColumn);
  330.             END;
  331.  
  332.         cellsRead := 0;
  333.         FOR i := 1 TO scrapInfo.noOfCells DO
  334.             BEGIN
  335.             ReadScrap(calcScrap, scrapOffset, @cellCoord, SIZEOF(cellCoord));
  336.             aCell := clipDocument.GetCell(cellCoord.v, cellCoord.h);
  337.             aCell.ReadFromScrap(calcScrap, scrapOffset);
  338.             cellsRead := cellsRead + 1;
  339.             END;
  340.  
  341.         {$IFC qDebug}
  342.         IF gIntenseDebugging THEN
  343.             BEGIN
  344.             WRITELN('MakeViewForAlienClipboard: cellsRead=', cellsRead: 0, ', scrapInfo.noOfCells=',
  345.                     scrapInfo.noOfCells);
  346.             IF cellsRead <> scrapInfo.noOfCells THEN
  347.                 ProgramBreak('MakeViewForAlienClipboard: Wrong number of cells');
  348.             END;
  349.         {$ENDC}
  350.  
  351.         calcScrap := DisposeIfHandle(calcScrap);
  352.  
  353.         Success(fi);
  354.         MakeViewForAlienClipboard := clipView;
  355.         END
  356.     ELSE
  357.         MakeViewForAlienClipboard := INHERITED MakeViewForAlienClipboard;
  358.     END;
  359.  
  360. {***************************************************************************************************
  361.     T C a l c D o c u m e n t
  362. ***************************************************************************************************}
  363. {$S AOpen}
  364.  
  365. PROCEDURE TCalcDocument.ICalcDocument(dimensions: Rect);
  366.  
  367.     VAR
  368.         r:                    RowNumber;
  369.         c:                    ColumnNumber;
  370.         aRect:                Rect;
  371.  
  372.     BEGIN
  373.     IDocument(kFileType, kSignature, kUsesDataFork, NOT kUsesRsrcFork, NOT kDataOpen,
  374.               NOT kRsrcOpen);
  375.  
  376.     fSavePrintInfo := TRUE;                             { the 'print info' record of the
  377.                                                          fDocPrintHandler will be written out to
  378.                                                          the data fork }
  379.  
  380.     fDimensions := dimensions;
  381.     WITH dimensions DO
  382.         BEGIN
  383.         fRowOffset := top - 1;
  384.         fColumnOffset := left - 1;
  385.         fNoOfRows := bottom - top + 1;
  386.         fNoOfColumns := right - left + 1;
  387.         END;
  388.     fCalcMode := kCalcMode;
  389.     fSelectionType := NoSelection;
  390.  
  391.     fCellsView := NIL;
  392.     fRowsView := NIL;
  393.     fColumnsView := NIL;
  394.     fEntryView := NIL;
  395.     fCoordView := NIL;
  396.  
  397.     fEditRow := 0;
  398.     fEditColumn := 0;
  399.     fEditCell := NIL;
  400.  
  401.     { Initialize cells, rows and columns }
  402.     FOR r := 1 TO fNoOfRows DO
  403.         BEGIN
  404.         fRows[r] := NIL;
  405.         FOR c := 1 TO fNoOfColumns DO
  406.             BEGIN
  407.             fCells[r, c] := NIL;
  408.             END;
  409.         END;
  410.  
  411.     FOR c := 1 TO fNoOfColumns DO
  412.         fColumns[c] := NIL;
  413.  
  414.     SetRect(aRect, 1, 1, 1, 1);
  415.     fInUseBounds := aRect;
  416.     END;
  417.  
  418. {--------------------------------------------------------------------------------------------------}
  419. {$S AClose}
  420.  
  421. PROCEDURE TCalcDocument.Free;
  422.  
  423.     BEGIN
  424.     FreeData;
  425.  
  426.     INHERITED Free;
  427.     END;
  428.  
  429. {--------------------------------------------------------------------------------------------------}
  430. {$S ADoCommand}
  431.  
  432. PROCEDURE TCalcDocument.AddCell(theCell: TCell;
  433.                                 r: RowNumber;
  434.                                 c: ColumnNumber);
  435.  
  436.     VAR
  437.         aRect:                Rect;
  438.  
  439.     BEGIN
  440.     fCells[r, c] := theCell;
  441.     fAllocatedCells := fAllocatedCells + 1;
  442.  
  443.     SetRect(aRect, c, r, c, r);
  444.     {$Push} {$H-}
  445.     UnionRect(aRect, fInUseBounds, fInUseBounds);
  446.     {$Pop}
  447.  
  448.     WITH theCell DO
  449.         BEGIN
  450.         fCalcDocument := SELF;
  451.         fRow := r;
  452.         fColumn := c;
  453.         END;
  454.     END;
  455.  
  456. {--------------------------------------------------------------------------------------------------}
  457. {$S ADoCommand}
  458.  
  459. PROCEDURE TCalcDocument.AddColumn(theColumn: TColumn);
  460.  
  461.     BEGIN
  462.     fColumns[theColumn.fNumber] := theColumn;
  463.     fAllocatedColumns := fAllocatedColumns + 1;
  464.  
  465.     fInUseBounds.left := Min(fInUseBounds.left, theColumn.fNumber);
  466.     fInUseBounds.right := Max(fInUseBounds.right, theColumn.fNumber);
  467.     END;
  468.  
  469. {--------------------------------------------------------------------------------------------------}
  470. {$S ADoCommand}
  471.  
  472. PROCEDURE TCalcDocument.AddRow(theRow: TRow);
  473.  
  474.     BEGIN
  475.     fRows[theRow.fNumber] := theRow;
  476.     fAllocatedRows := fAllocatedRows + 1;
  477.  
  478.     fInUseBounds.top := Min(fInUseBounds.top, theRow.fNumber);
  479.     fInUseBounds.bottom := Max(fInUseBounds.bottom, theRow.fNumber);
  480.     END;
  481.  
  482. {--------------------------------------------------------------------------------------------------}
  483. {$S ARes}
  484.  
  485. FUNCTION TCalcDocument.CellExists(r: RowNumber;
  486.                                   c: ColumnNumber): BOOLEAN;
  487.  
  488.     BEGIN
  489.     CellExists := (r > 0) & (r <= kMaxRows) & (c > 0) & (c <= kMaxColumns) & (fCells[r, c] <> NIL) &
  490.                   (NOT fCells[r, c].fDeleted);
  491.     END;
  492.  
  493. {--------------------------------------------------------------------------------------------------}
  494. {$S ADoCommand}
  495.  
  496. FUNCTION TCalcDocument.CellInRange(r: INTEGER;
  497.                                    c: INTEGER;
  498.                                    range: Rect): BOOLEAN;
  499.  
  500.     BEGIN
  501.     WITH range DO
  502.         CellInRange := (r >= top) & (r <= bottom) & (c >= left) & (c <= right);
  503.     END;
  504.  
  505. {--------------------------------------------------------------------------------------------------}
  506. {$S ADoCommand}
  507.  
  508. FUNCTION TCalcDocument.ColumnExists(c: ColumnNumber): BOOLEAN;
  509.  
  510.     BEGIN
  511.     ColumnExists := (c > 0) & (c <= kMaxColumns) & (fColumns[c] <> NIL);
  512.     END;
  513.  
  514. {--------------------------------------------------------------------------------------------------}
  515. {$S ADoCommand}
  516.  
  517. PROCEDURE TCalcDocument.ConstrainToUsedCells(VAR cellRange: Rect);
  518.  { Given a range of cells, this returns the range of cells that fall
  519.    within the range of used cells.    This is used to optimize
  520.    performance so that we don't try to operate on cells that
  521.    we know have never been used (i.e. allocated). }
  522.  
  523.     BEGIN
  524.     WITH cellRange DO
  525.         BEGIN
  526.         top := Max(top, fInUseBounds.top);
  527.         left := Max(left, fInUseBounds.left);
  528.         bottom := Min(bottom, fInUseBounds.bottom);
  529.         right := Min(right, fInUseBounds.right);
  530.         END;
  531.     END;
  532.  
  533. {--------------------------------------------------------------------------------------------------}
  534. {$S ARes}
  535.  
  536. PROCEDURE TCalcDocument.DeleteCell(r: RowNumber;
  537.                                    c: ColumnNumber);
  538.  
  539.     VAR
  540.         theCell:            TCell;
  541.  
  542.     BEGIN
  543.     theCell := GetExistingCell(r, c);
  544.     IF theCell <> NIL THEN
  545.         BEGIN
  546.         theCell.SetDeleteState(TRUE);
  547.         fAllocatedCells := fAllocatedCells - 1;
  548.         IF theCell = fEditCell THEN
  549.             fEntryView.SetToString('');
  550.         END;
  551.     END;
  552.  
  553. {--------------------------------------------------------------------------------------------------}
  554. {$S AOpen}
  555.  
  556. PROCEDURE TCalcDocument.DoInitialState; OVERRIDE;
  557.  
  558.     BEGIN
  559.     fAllocatedCells := 0;
  560.     fAllocatedRows := 0;
  561.     fAllocatedColumns := 0;
  562.     END;
  563.  
  564. {--------------------------------------------------------------------------------------------------}
  565. {$S AOpen}
  566.  
  567. PROCEDURE TCalcDocument.DoMakeViews(forPrinting: BOOLEAN);
  568.  
  569.     VAR
  570.         aCalcWindow:        TCalcWindow;
  571.         aTEntryView:        TEntryView;
  572.         aCellsView:         TCellsView;
  573.         aColumnsView:        TColumnsView;
  574.         aRowsView:            TRowsView;
  575.         aCoordView:         TCoordView;
  576.         aRowScroller:        TSecondaryScroller;
  577.         aColumnScroller:    TSecondaryScroller;
  578.         aCalcScroller:        TPrimaryScroller;
  579.         aPrintHandler:        TCalcPrintHandler;
  580.  
  581.     PROCEDURE SetColumnWidths;
  582.  
  583.         VAR
  584.             c:                    ColumnNumber;
  585.             newWidth:            INTEGER;
  586.  
  587.         BEGIN
  588.         FOR c := 1 TO fNoOfColumns DO
  589.             IF fColumns[c] <> NIL THEN
  590.                 BEGIN
  591.                 newWidth := fColumns[c].fWidth;
  592.                 IF newWidth <> kCellWidth THEN
  593.                     BEGIN
  594.                     fCellsView.SetColWidth(c, 1, newWidth);
  595.                     fColumnsView.SetColWidth(c, 1, newWidth);
  596.                     END;
  597.                 END;
  598.         END;
  599.  
  600.     BEGIN
  601.     aCalcWindow := TCalcWindow(NewTemplateWindow(kCalcWindowType, SELF));
  602.     WITH aCalcWindow DO
  603.         BEGIN
  604.         aCellsView := TCellsView(FindSubView('CELL'));
  605.         aRowsView := TRowsView(FindSubView('ROWS'));
  606.         aColumnsView := TColumnsView(FindSubView('COLS'));
  607.         aTEntryView := TEntryView(FindSubView('ENTV'));
  608.         aCoordView := TCoordView(FindSubView('CORD'));
  609.         END;
  610.  
  611.     fCellsView := aCellsView;
  612.     fRowsView := aRowsView;
  613.     fColumnsView := aColumnsView;
  614.     fEntryView := aTEntryView;
  615.     fCoordView := aCoordView;
  616.  
  617.     IF NOT forPrinting THEN
  618.         BEGIN
  619.         aTEntryView.fText := NewPermHandle(0);
  620.         FailNIL(aTEntryView.fText);
  621.         aTEntryView.StuffText(aTEntryView.fText);        { Stuff the initial text in }
  622.         END;
  623.  
  624.     { Insert the entry view between the cell's view and its scroller in the target chain }
  625.     aCalcWindow.SetTarget(aCellsView);
  626.     aTEntryView.fNextHandler := aCellsView.fNextHandler;
  627.     aCellsView.fNextHandler := aTEntryView;
  628.  
  629.     { set up the cells view scroller to scroll the rows and columns too }
  630.     aCalcScroller := TPrimaryScroller(aCellsView.GetScroller(TRUE));
  631.     aCalcScroller.SetScrollParameters(kCellWidth, kCellHeight, TRUE, TRUE);
  632.  
  633.     aColumnScroller := TSecondaryScroller(aColumnsView.GetScroller(TRUE));
  634.     aColumnScroller.SetScrollParameters(kCellWidth, 0, TRUE, TRUE);
  635.  
  636.     aRowScroller := TSecondaryScroller(aRowsView.GetScroller(TRUE));
  637.     aRowScroller.SetScrollParameters(0, kCellHeight, TRUE, TRUE);
  638.  
  639.     aCalcScroller.AddSecondaryScroller(aRowScroller, kNotHDependent, kVDependent);
  640.     aCalcScroller.AddSecondaryScroller(aColumnScroller, kHDependent, kNotVDependent);
  641.  
  642.     NEW(aPrintHandler);
  643.     FailNIL(aPrintHandler);
  644.     aPrintHandler.IStdPrintHandler(SELF,                { its document }
  645.                                    aCellsView,            { its view }
  646.                                    NOT kSquareDots,     { does not have square dots }
  647.                                    NOT kFixedSize,        { horizontal page size is variable }
  648.                                    kFixedSize);         { vertical page size is fixed }
  649.     aPrintHandler.fMinimalMargins := FALSE;
  650.  
  651.     SetColumnWidths;                                    { get existing document's column widths }
  652.  
  653.     IF forPrinting THEN                                 { Finder printing }
  654.         aPrintHandler.RedoPageBreaks
  655.     ELSE
  656.         BEGIN
  657.         ShowReverted;                                    { display the views }
  658.  
  659.         fEditRow := 1;                                    { default cell to edit is A1 }
  660.         fEditColumn := 1;
  661.         SetEntry(fEditRow, fEditColumn);
  662.         fSelectionType := CellSelection;
  663.         fCellsView.SelectCell(GridCell($00010001), kDontExtend, kDontHighlight, kSelect);
  664.         END;
  665.     END;
  666.  
  667. {--------------------------------------------------------------------------------------------------}
  668. {$S ASelCommand}
  669.  
  670. FUNCTION TCalcDocument.DoMenuCommand(aCmdNumber: cmdNumber): TCommand;
  671.  
  672.     VAR
  673.         aColumnFormatter:    TColumnFormatter;
  674.  
  675.     BEGIN                                                { TCalcDocument.DoMenuCommand }
  676.     DoMenuCommand := NIL;
  677.     CASE aCmdNumber OF
  678.         cRecalculate:
  679.             DoRecalculate(kForceAutomatic, kSetDependents);
  680.         cAutoCalc:
  681.             BEGIN
  682.             fCalcMode := Automatic;
  683.             DoRecalculate(kForceAutomatic, kSetDependents);
  684.             END;
  685.         cManualCalc:
  686.             fCalcMode := Manual;
  687.  
  688.         cGeneral, cNoDecimal, cDecimal, cScientific, cSystemJustify, cForceLeftJustify, cRightJustify, cCenter:
  689.             BEGIN
  690.             NEW(aColumnFormatter);
  691.             FailNIL(aColumnFormatter);
  692.             aColumnFormatter.IFormatter(SELF, aCmdNumber);
  693.             DoMenuCommand := aColumnFormatter;
  694.             END;
  695.  
  696.         OTHERWISE
  697.             DoMenuCommand := INHERITED DoMenuCommand(aCmdNumber);
  698.     END;
  699.     END;
  700.  
  701. {--------------------------------------------------------------------------------------------------}
  702. {$S AWriteFile}
  703.  
  704. PROCEDURE TCalcDocument.DoNeedDiskSpace(VAR dataForkBytes, rsrcForkBytes: LONGINT);
  705.  
  706.     VAR
  707.         r:                    Rect;
  708.  
  709. {--------------------------------------------------------------------------------------------------}
  710.  
  711.     PROCEDURE AccountForCell(aCell: GridCell);
  712.  
  713.         BEGIN
  714.         dataForkBytes := dataForkBytes + GetCell(aCell.v, aCell.h).GetDiskSize(FALSE);
  715.         END;
  716.  
  717.     BEGIN
  718.     { get Print record requirements }
  719.     INHERITED DoNeedDiskSpace(dataForkBytes, rsrcForkBytes);
  720.  
  721.     dataForkBytes := dataForkBytes + SIZEOF(CalcDocDiskInfo) + SIZEOF(RowDiskInfo) *
  722.                      fAllocatedRows + SIZEOF(ColumnDiskInfo) * fAllocatedColumns;
  723.     r := fInUseBounds;
  724.     EachExistingCellDo(r, AccountForCell);
  725.  
  726.     END;
  727.  
  728. {--------------------------------------------------------------------------------------------------}
  729. {$S AReadFile}
  730.  
  731. PROCEDURE TCalcDocument.DoRead(aRefNum: INTEGER;
  732.                                rsrcExists, forPrinting: BOOLEAN);
  733.  
  734.     VAR
  735.         i:                    INTEGER;
  736.         noOfCells:            INTEGER;
  737.         noOfRows:            INTEGER;
  738.         noOfColumns:        INTEGER;
  739.         r:                    RowNumber;
  740.         c:                    ColumnNumber;
  741.         aCell:                TCell;
  742.         aRow:                TRow;
  743.         aColumn:            TColumn;
  744.         fi:                 FailInfo;
  745.  
  746. {--------------------------------------------------------------------------------------------------}
  747.  
  748.     PROCEDURE ReadDocInfo;
  749.  
  750.         VAR
  751.             theDocInfo:         CalcDocDiskInfo;
  752.  
  753.         BEGIN
  754.         ReadBytes(aRefNum, SIZEOF(theDocInfo), @theDocInfo);
  755.  
  756.         WITH theDocInfo DO
  757.             BEGIN
  758.             fDimensions := dimensions;
  759.             fCalcMode := calcMode;
  760.             noOfRows := allocatedRows;
  761.             noOfColumns := allocatedColumns;
  762.             fAllocatedCells := allocatedCells;
  763.             fSelectionType := NoSelection;
  764.             fEditRow := editRow;
  765.             fEditColumn := editColumn;
  766.             END;
  767.  
  768.         WITH fDimensions DO
  769.             BEGIN
  770.             fNoOfRows := bottom - top + 1;
  771.             fNoOfColumns := right - left + 1;
  772.             END;
  773.  
  774.   { Save the number of cells to be read, then set fAllocatedCells to
  775.     zero.  As each cell is read fAllocatedCells is incremented.
  776.     When we've finished, noOfCells must equal fAllocatedCells. }
  777.         noOfCells := fAllocatedCells;
  778.         DoInitialState;                                 { clear allocation counts }
  779.         END;
  780.  
  781. {--------------------------------------------------------------------------------------------------}
  782.  
  783.     PROCEDURE HdlReadFailure(error: OSErr;
  784.                              message: LONGINT);
  785.  
  786.         BEGIN
  787.         { Oh Boy are we in trouble }
  788.   { Need to set back rows and columns to reflect the number read in so
  789.     the freedata routine (which will eventually be called by other
  790.     failure handlers on the stack) won't try to free unallocated objects}
  791.         IF c = 0 THEN
  792.             BEGIN
  793.             { We died while reading the rows in}
  794.             fNoOfRows := r - 1;
  795.             fNoOfColumns := 0;
  796.             END
  797.         ELSE IF i = 0 THEN
  798.             BEGIN
  799.             { Died in the columns }
  800.             fNoOfColumns := c - 1;
  801.             END;
  802.         END;
  803.  
  804.     BEGIN                                                { DoRead }
  805.     CatchFailures(fi, HdlReadFailure);
  806.     INHERITED DoRead(aRefNum, rsrcExists, forPrinting);
  807.  
  808.     ReadDocInfo;                                        { Get info about the document }
  809.     r := 0; c := 0; i := 0;                             { Initialized so failure handler knows where
  810.                                                          we died }
  811.  
  812.     FOR i := 1 TO noOfRows DO                            { Get info about each row }
  813.         BEGIN
  814.         ReadBytes(aRefNum, SIZEOF(r), @r);
  815.         aRow := GetRow(r);
  816.         aRow.ReadFromDisk(aRefNum);
  817.         END;
  818.  
  819.     FOR i := 1 TO noOfColumns DO                        { Get info about each column }
  820.         BEGIN
  821.         ReadBytes(aRefNum, SIZEOF(c), @c);
  822.         aColumn := GetColumn(c);
  823.         aColumn.ReadFromDisk(aRefNum);
  824.         END;
  825.  
  826.     FOR i := 1 TO noOfCells DO                            { Read in the cells }
  827.         BEGIN
  828.         ReadCellCoordinate(aRefNum, r, c);
  829.         aCell := GetCell(r, c);
  830.         aCell.ReadFromDisk(aRefNum);
  831.         END;
  832.  
  833.     {$IFC qDebug}
  834.     IF gIntenseDebugging THEN
  835.         BEGIN
  836.         WRITELN('TCalcDocument.DoRead: noOfCells=', noOfCells);
  837.         IF noOfCells <> fAllocatedCells THEN
  838.             BEGIN
  839.             WRITELN('TCalcDocument.DoRead: Wrong number of cells.  noOfCells=', noOfCells,
  840.                     ', fAllocatedCells=', fAllocatedCells);
  841.             ProgramBreak('');
  842.             END;
  843.         END;
  844.     {$ENDC}
  845.  
  846.     Success(fi);
  847.     END;                                                { DoRead }
  848.  
  849. {--------------------------------------------------------------------------------------------------}
  850. {$S ADoCommand}
  851.  
  852. PROCEDURE TCalcDocument.DoRecalculate(forceAutomatic: BOOLEAN;
  853.                                       setDependents: BOOLEAN);
  854.  
  855.     VAR
  856.         r:                    Rect;
  857.  
  858. {--------------------------------------------------------------------------------------------------}
  859.  
  860.     PROCEDURE RecalcCell(aCell: GridCell);
  861.  
  862.         BEGIN
  863.         GetCell(aCell.v, aCell.h).Recalculate(forceAutomatic, setDependents);
  864.         END;
  865.  
  866. {--------------------------------------------------------------------------------------------------}
  867.  
  868.     PROCEDURE RecalcExistingCell(aCell: GridCell);
  869.  
  870.         VAR
  871.             theCell:            TCell;
  872.  
  873.         BEGIN
  874.         theCell := GetExistingCell(aCell.v, aCell.h);
  875.         IF theCell <> NIL THEN
  876.             theCell.Recalculate(forceAutomatic, setDependents);
  877.         END;
  878.  
  879.     BEGIN
  880.     IF IsAutoCalc | forceAutomatic THEN
  881.         BEGIN
  882.         r := fInUseBounds;
  883.         EachExistingCellDo(r, RecalcCell);
  884.         END
  885.     ELSE
  886.         fCellsView.EachSelectedCellDo(RecalcExistingCell);
  887.     SetChangeCount(Max(fChangeCount + 1, 1));            { enable Save - document may have changed }
  888.     END;
  889.  
  890. {--------------------------------------------------------------------------------------------------}
  891. {$S ARes}
  892.  
  893. PROCEDURE TCalcDocument.DoSetupMenus; OVERRIDE;
  894.  
  895.     VAR
  896.         justification:        INTEGER;
  897.         Style:                TypeOfStyle;
  898.         columnFormat:        FormatRecord;
  899.  
  900.     BEGIN
  901.  
  902.     INHERITED DoSetupMenus;
  903.  
  904.     Enable(cRecalculate, TRUE);
  905.     EnableCheck(cAutoCalc, TRUE, IsAutoCalc);
  906.     EnableCheck(cManualCalc, TRUE, fCalcMode = Manual);
  907.  
  908.     IF fColumnIsSelected THEN
  909.         BEGIN
  910.         IF ColumnExists(fEditColumn) THEN
  911.             columnFormat := GetColumn(fEditColumn).fFormat
  912.         ELSE
  913.             columnFormat := gDefaultFormat;
  914.         justification := columnFormat.fJustification;
  915.         Style := columnFormat.fStyle;
  916.  
  917.         EnableCheck(cSystemJustify, TRUE, justification = teJustSystem);
  918.         EnableCheck(cForceLeftJustify, TRUE, justification = teForceLeft);
  919.         EnableCheck(cRightJustify, TRUE, justification = TEJustRight);
  920.         EnableCheck(cCenter, TRUE, justification = TEJustCenter);
  921.  
  922.         EnableCheck(cGeneral, TRUE, Style = General);
  923.         EnableCheck(cDecimal, TRUE, Style = DecimalStyle);
  924.         EnableCheck(cNoDecimal, TRUE, Style = NoDecimal);
  925.         EnableCheck(cScientific, TRUE, Style = Scientific);
  926.         END
  927.     ELSE
  928.         BEGIN
  929.         Enable(cSystemJustify, FALSE);
  930.         Enable(cForceLeftJustify, FALSE);
  931.         Enable(cRightJustify, FALSE);
  932.         Enable(cCenter, FALSE);
  933.  
  934.         Enable(cGeneral, FALSE);
  935.         Enable(cDecimal, FALSE);
  936.         Enable(cNoDecimal, FALSE);
  937.         Enable(cScientific, FALSE);
  938.         END;
  939.  
  940.     END;
  941.  
  942. {--------------------------------------------------------------------------------------------------}
  943. {$S AWriteFile}
  944.  
  945. PROCEDURE TCalcDocument.DoWrite(aRefNum: INTEGER;
  946.                                 makingCopy: BOOLEAN);
  947.  
  948.     VAR
  949.         cellsWritten:        INTEGER;
  950.         r:                    Rect;
  951.  
  952. {--------------------------------------------------------------------------------------------------}
  953.  
  954.     PROCEDURE WriteDocInfo;
  955.  
  956.         VAR
  957.             theDocInfo:         CalcDocDiskInfo;
  958.  
  959.         BEGIN
  960.         WITH theDocInfo DO
  961.             BEGIN
  962.             dimensions := fDimensions;
  963.             calcMode := fCalcMode;
  964.             allocatedRows := fAllocatedRows;
  965.             allocatedColumns := fAllocatedColumns;
  966.             allocatedCells := fAllocatedCells;
  967.             selectionType := NoSelection;
  968.             editRow := fEditRow;
  969.             editColumn := fEditColumn;
  970.             END;
  971.         WriteBytes(aRefNum, SIZEOF(theDocInfo), @theDocInfo);
  972.         END;
  973.  
  974. {--------------------------------------------------------------------------------------------------}
  975.  
  976.     PROCEDURE WriteRow(aCell: GridCell);
  977.  
  978.         BEGIN
  979.         GetRow(aCell.v).WriteToDisk(aRefNum);
  980.         END;
  981.  
  982. {--------------------------------------------------------------------------------------------------}
  983.  
  984.     PROCEDURE WriteColumn(aCell: GridCell);
  985.  
  986.         VAR
  987.             theColumn:            TColumn;
  988.  
  989.         BEGIN
  990.         theColumn := GetColumn(aCell.h);
  991.         theColumn.fWidth := fColumnsView.GetColWidth(aCell.h);
  992.         theColumn.WriteToDisk(aRefNum);
  993.         END;
  994.  
  995. {--------------------------------------------------------------------------------------------------}
  996.  
  997.     PROCEDURE WriteCell(aCell: GridCell);
  998.  
  999.         BEGIN
  1000.         GetCell(aCell.v, aCell.h).WriteToDisk(aRefNum);
  1001.         cellsWritten := cellsWritten + 1;
  1002.         END;
  1003.  
  1004.     BEGIN
  1005.     INHERITED DoWrite(aRefNum, makingCopy);
  1006.  
  1007.     WriteDocInfo;                                        { Write info about the document }
  1008.  
  1009.     EachExistingRowDo(WriteRow);                        { Write info about each row }
  1010.     EachExistingColumnDo(WriteColumn);                    { Write info about each column }
  1011.  
  1012.     cellsWritten := 0;
  1013.     r := fInUseBounds;
  1014.     EachExistingCellDo(r, WriteCell);                    { Write out the cells }
  1015.  
  1016.     {$IFC qDebug}
  1017.     IF cellsWritten <> fAllocatedCells THEN
  1018.         ProgramBreak('DoWrite: Incorrect number of cells written');
  1019.     {$ENDC}
  1020.     END;
  1021.  
  1022. {--------------------------------------------------------------------------------------------------}
  1023. {$S ARes}
  1024.  
  1025. PROCEDURE TCalcDocument.EachExistingRowDo(PROCEDURE
  1026.                                           DoToCell(aCell: GridCell));
  1027. { Perform DoToCell for each ALLOCATED Row }
  1028.  
  1029.     VAR
  1030.         r:                    RowNumber;
  1031.         aCell:                GridCell;
  1032.         aRect:                Rect;
  1033.  
  1034.     BEGIN
  1035.     aRect := fInUseBounds;
  1036.     WITH aRect DO
  1037.         BEGIN
  1038.         FOR r := top TO bottom DO
  1039.             BEGIN
  1040.             IF RowExists(r) THEN
  1041.                 BEGIN
  1042.                 aCell.h := 1;
  1043.                 aCell.v := r;
  1044.                 DoToCell(aCell);
  1045.                 END;
  1046.             END;
  1047.         END;
  1048.     END;
  1049.  
  1050. {--------------------------------------------------------------------------------------------------}
  1051. {$S ARes}
  1052.  
  1053. PROCEDURE TCalcDocument.EachExistingColumnDo(PROCEDURE
  1054.                                              DoToCell(aCell: GridCell));
  1055. { Perform DoToCell for each ALLOCATED Column }
  1056.  
  1057.     VAR
  1058.         c:                    ColumnNumber;
  1059.         aCell:                GridCell;
  1060.         aRect:                Rect;
  1061.  
  1062.     BEGIN
  1063.     aRect := fInUseBounds;
  1064.     WITH aRect DO
  1065.         BEGIN
  1066.         FOR c := left TO right DO
  1067.             BEGIN
  1068.             IF ColumnExists(c) THEN
  1069.                 BEGIN
  1070.                 aCell.h := c;
  1071.                 aCell.v := 1;
  1072.                 DoToCell(aCell);
  1073.                 END;
  1074.             END;
  1075.         END;
  1076.     END;
  1077.  
  1078. {--------------------------------------------------------------------------------------------------}
  1079. {$S ARes}
  1080.  
  1081. PROCEDURE TCalcDocument.EachExistingCellDo(cellRange: Rect;
  1082.                                            PROCEDURE
  1083.                                            DoToCell(aCell: GridCell));
  1084. { Perform DoToCell for each ALLOCATED cell within a range of cells. }
  1085.  
  1086.     VAR
  1087.         r:                    RowNumber;
  1088.         c:                    ColumnNumber;
  1089.         aCell:                GridCell;
  1090.  
  1091.     BEGIN
  1092.     ConstrainToUsedCells(cellRange);
  1093.     WITH cellRange DO
  1094.         BEGIN
  1095.         FOR r := top TO bottom DO
  1096.             BEGIN
  1097.             FOR c := left TO right DO
  1098.                 BEGIN
  1099.                 IF CellExists(r, c) THEN
  1100.                     BEGIN
  1101.                     aCell.h := c;
  1102.                     aCell.v := r;
  1103.                     DoToCell(aCell);
  1104.                     END;
  1105.                 END;
  1106.             END;
  1107.         END;
  1108.     END;
  1109.  
  1110. {--------------------------------------------------------------------------------------------------}
  1111. {$S ADoCommand}
  1112.  
  1113. PROCEDURE TCalcDocument.EditCell;
  1114. { Change the formula of the cell being edited to the string in the entry view }
  1115.  
  1116.     VAR
  1117.         theString:            Str255;
  1118.  
  1119.     BEGIN
  1120.     fEntryView.GetAsString(theString);
  1121.     IF fEditCell = NIL THEN
  1122.         fEditCell := GetCell(fEditRow, fEditColumn);
  1123.     fEditCell.SetToString(theString);
  1124.     END;
  1125.  
  1126. {--------------------------------------------------------------------------------------------------}
  1127. {$S AFields}
  1128.  
  1129. PROCEDURE TCalcDocument.Fields(PROCEDURE DoToField(fieldName: Str255;
  1130.                                                    fieldAddr: Ptr;
  1131.                                                    fieldType: INTEGER)); OVERRIDE;
  1132.  
  1133.     VAR
  1134.         aString:            Str255;
  1135.  
  1136.     BEGIN
  1137.     DoToField('TCalcDocument', NIL, bClass);
  1138.     DoToField('fEditCell', @fEditCell, bObject);
  1139.     DoToField('fNoOfRows', @fNoOfRows, bInteger);
  1140.     DoToField('fNoOfColumns', @fNoOfColumns, bInteger);
  1141.     DoToField('fColumns', @fColumns, bObject);
  1142.     DoToField('fRows', @fRows, bObject);
  1143.     DoToField('fRowOffset', @fRowOffset, bInteger);
  1144.     DoToField('fColumnOffset', @fColumnOffset, bInteger);
  1145.     DoToField('fCellsView', @fCellsView, bObject);
  1146.     DoToField('fRowsView', @fRowsView, bObject);
  1147.     DoToField('fColumnsView', @fColumnsView, bObject);
  1148.     DoToField('fEntryView', @fEntryView, bObject);
  1149.     DoToField('fCoordView', @fCoordView, bObject);
  1150.     DoToField('fDimensions', @fDimensions, bRect);
  1151.     DoToField('fInUseBounds', @fInUseBounds, bRect);
  1152.     IF IsAutoCalc THEN
  1153.         aString := 'Automatic'
  1154.     ELSE
  1155.         aString := 'Manual';
  1156.     DoToField('fCalcMode', @aString, bString);
  1157.     DoToField('fAllocatedRows', @fAllocatedRows, bInteger);
  1158.     DoToField('fAllocatedColumns', @fAllocatedColumns, bInteger);
  1159.     DoToField('fAllocatedCells', @fAllocatedCells, bInteger);
  1160.     CASE fSelectionType OF
  1161.         NoSelection:
  1162.             aString := 'NoSelection';
  1163.         CellSelection:
  1164.             aString := 'CellSelection';
  1165.         RowSelection:
  1166.             aString := 'RowSelection';
  1167.         ColumnSelection:
  1168.             aString := 'ColumnSelection';
  1169.         AllSelection:
  1170.             aString := 'AllSelection';
  1171.     END;
  1172.     DoToField('fSelectionType', @aString, bString);
  1173.     DoToField('fEditRow', @fEditRow, bByte);
  1174.     DoToField('fEditColumn', @fEditColumn, bByte);
  1175.     INHERITED Fields(DoToField);
  1176.     END;
  1177.  
  1178. {--------------------------------------------------------------------------------------------------}
  1179. {$S ARes}
  1180.  
  1181. PROCEDURE TCalcDocument.FreeCell(theCell: TCell);
  1182.  
  1183.     PROCEDURE RemoveReferences(theObject: TObject);
  1184.     { remove any reference to cell that is about to be freed }
  1185.  
  1186.         BEGIN
  1187.         IF IsObject(theObject) THEN                     { may have been freed }
  1188.             BEGIN
  1189.             TCell(theObject).fReferences.Delete(theCell);
  1190.             END;
  1191.         END;
  1192.  
  1193.     BEGIN
  1194.     {$IFC qDebug}
  1195.     IF fCells[theCell.fRow, theCell.fColumn] <> theCell THEN
  1196.         ProgramBreak('TCalcDocument.FreeCell: Cell table inconsistent');
  1197.     {$ENDC}
  1198.  
  1199.     fCells[theCell.fRow, theCell.fColumn] := NIL;
  1200.     IF theCell.fDependents <> NIL THEN
  1201.         theCell.fDependents.Each(RemoveReferences);
  1202.  
  1203.     FreeIfObject(theCell);
  1204.     theCell := NIL;
  1205.     END;
  1206.  
  1207. {--------------------------------------------------------------------------------------------------}
  1208. {$S ARes}
  1209.  
  1210. PROCEDURE TCalcDocument.FreeData;
  1211.  
  1212.     VAR
  1213.         r:                    RowNumber;
  1214.         c:                    ColumnNumber;
  1215.         oldState:            BOOLEAN;
  1216.  
  1217.     BEGIN
  1218.     oldState := Lock(TRUE);                             { HLock(Handle(SELF)) }
  1219.     WITH fInUseBounds DO
  1220.         FOR r := top TO bottom DO
  1221.             FOR c := left TO right DO
  1222.                 IF fCells[r, c] <> NIL THEN
  1223.                 {$Push} {$H-}
  1224.                     FreeCell(fCells[r, c]);
  1225.     {$Pop}
  1226.  
  1227.     FOR r := 1 TO fNoOfRows DO
  1228.         BEGIN
  1229.         FreeIfObject(fRows[r]);                                { This is paranoia setting in}
  1230.         fRows[r] := NIL;
  1231.         END;
  1232.  
  1233.     FOR c := 1 TO fNoOfColumns DO
  1234.         BEGIN
  1235.         FreeIfObject(fColumns[c]);                            { I admit it - I'm paranoid}
  1236.         fColumns[c] := NIL;
  1237.         END;
  1238.  
  1239.     IF Lock(oldState) THEN;
  1240.     END;
  1241.  
  1242. {--------------------------------------------------------------------------------------------------}
  1243. {$S ADoCommand}
  1244.  
  1245. PROCEDURE TCalcDocument.FreeDeletedCells;
  1246. { Free each deleted cell. }
  1247.  
  1248.     VAR
  1249.         r:                    RowNumber;
  1250.         c:                    ColumnNumber;
  1251.         theCell:            TCell;
  1252.         cellRange:            Rect;
  1253.  
  1254.     BEGIN
  1255.     cellRange := fInUseBounds;
  1256.     WITH cellRange DO
  1257.         FOR r := top TO bottom DO
  1258.             FOR c := left TO right DO
  1259.                 BEGIN
  1260.                 theCell := fCells[r, c];
  1261.                 IF (theCell <> NIL) & theCell.fDeleted THEN
  1262.                     FreeCell(theCell);
  1263.                 END;
  1264.     END;
  1265.  
  1266. {--------------------------------------------------------------------------------------------------}
  1267. {$S ARes}
  1268.  
  1269. FUNCTION TCalcDocument.GetCell(r: RowNumber;
  1270.                                c: ColumnNumber): TCell;
  1271.  { Return the cell object for the given coordinates.  If a cell object
  1272.    doesn't already exist, create one. }
  1273.  
  1274.     VAR
  1275.         theCell:            TCell;
  1276.  
  1277.     BEGIN
  1278.     IF CellExists(r, c) THEN
  1279.         theCell := fCells[r, c]
  1280.     ELSE
  1281.         BEGIN
  1282.         NEW(theCell);
  1283.         FailNIL(theCell);
  1284.         theCell.ICell(SELF, r, c);
  1285.         AddCell(theCell, r, c);
  1286.         END;
  1287.  
  1288.     GetCell := theCell;
  1289.     END;
  1290.  
  1291. {--------------------------------------------------------------------------------------------------}
  1292. {$S ARes}
  1293.  
  1294. FUNCTION TCalcDocument.GetColumn(c: ColumnNumber): TColumn;
  1295.  
  1296.     VAR
  1297.         theColumn:            TColumn;
  1298.  
  1299.     BEGIN
  1300.     IF ColumnExists(c) THEN
  1301.         theColumn := fColumns[c]
  1302.     ELSE
  1303.         BEGIN
  1304.         NEW(theColumn);
  1305.         FailNIL(theColumn);
  1306.         theColumn.IColumn(c);
  1307.         AddColumn(theColumn);
  1308.         END;
  1309.  
  1310.     GetColumn := theColumn;
  1311.     END;
  1312.  
  1313. {--------------------------------------------------------------------------------------------------}
  1314. {$S ARes}
  1315.  
  1316. FUNCTION TCalcDocument.GetExistingCell(r: RowNumber;
  1317.                                        c: ColumnNumber): TCell;
  1318. { Like GetCell, only return NIL if the cell object doesn't exist }
  1319.  
  1320.     BEGIN
  1321.     IF CellExists(r, c) THEN
  1322.         GetExistingCell := fCells[r, c]
  1323.     ELSE
  1324.         GetExistingCell := NIL;
  1325.     END;
  1326.  
  1327. {--------------------------------------------------------------------------------------------------}
  1328. {$S ARes}
  1329.  
  1330. FUNCTION TCalcDocument.IsAutoCalc: BOOLEAN;
  1331.  
  1332.     BEGIN
  1333.     IsAutoCalc := fCalcMode = Automatic;
  1334.     END;
  1335.  
  1336. {--------------------------------------------------------------------------------------------------}
  1337. {$S ARes}
  1338.  
  1339. FUNCTION TCalcDocument.GetRow(r: RowNumber): TRow;
  1340.  
  1341.     VAR
  1342.         theRow:             TRow;
  1343.  
  1344.     BEGIN
  1345.     IF RowExists(r) THEN
  1346.         theRow := fRows[r]
  1347.     ELSE
  1348.         BEGIN
  1349.         NEW(theRow);
  1350.         FailNIL(theRow);
  1351.         theRow.IRow(r);
  1352.         AddRow(theRow);
  1353.         END;
  1354.  
  1355.     GetRow := theRow;
  1356.     END;
  1357.  
  1358. {--------------------------------------------------------------------------------------------------}
  1359. {$S ADoCommand}
  1360.  
  1361. FUNCTION TCalcDocument.RowExists(r: RowNumber): BOOLEAN;
  1362.  
  1363.     BEGIN
  1364.     RowExists := (r > 0) & (r <= kMaxRows) & (fRows[r] <> NIL);
  1365.     END;
  1366.  
  1367. {--------------------------------------------------------------------------------------------------}
  1368. {$S ADoCommand}
  1369.  
  1370. PROCEDURE TCalcDocument.SetEntry(r: RowNumber;
  1371.                                  c: ColumnNumber);
  1372. { Set the string in TEntryView to the formula in the cell }
  1373.  
  1374.     VAR
  1375.         theString:            Str255;
  1376.  
  1377.     BEGIN
  1378.     IF CellExists(r, c) THEN
  1379.         BEGIN
  1380.         fCells[r, c].GetAsString(theString);
  1381.         fEntryView.SetToString(theString);
  1382.         END
  1383.     ELSE
  1384.         fEntryView.SetToString('');
  1385.     END;
  1386.  
  1387. {--------------------------------------------------------------------------------------------------}
  1388. {$S ARes}
  1389.  
  1390. PROCEDURE TCalcDocument.UndeleteCell(r: RowNumber;
  1391.                                      c: ColumnNumber);
  1392.  
  1393.     BEGIN
  1394.     IF fCells[r, c] <> NIL THEN                         { can't use CellExists b/c it screens
  1395.                                                          deleted cells }
  1396.         BEGIN
  1397.         fCells[r, c].SetDeleteState(FALSE);
  1398.         fAllocatedCells := fAllocatedCells + 1;
  1399.         END;
  1400.     END;
  1401.  
  1402. {***************************************************************************************************
  1403.     T C a l c W i n d o w
  1404. ***************************************************************************************************}
  1405. {$S AOpen}
  1406.  
  1407. PROCEDURE TCalcWindow.IRes(itsDocument: TDocument;
  1408.                            itsSuperView: TView;
  1409.                            VAR itsParams: Ptr); OVERRIDE;
  1410.  
  1411.     VAR
  1412.         minSize:            Point;
  1413.  
  1414.     BEGIN
  1415.     INHERITED IRes(itsDocument, itsSuperView, itsParams);
  1416.     minSize.h := 284;
  1417.     minSize.v := 126;
  1418.     SetResizeLimits(minSize, gStdWSizeRect.botRight);
  1419.     END;
  1420.  
  1421. {--------------------------------------------------------------------------------------------------}
  1422. {$S ARes}
  1423.  
  1424. PROCEDURE TCalcWindow.Draw(area: Rect); OVERRIDE;
  1425.  
  1426.     BEGIN
  1427.     { draw the extra borders for the rows and columns views }
  1428.     PenNormal;
  1429.  
  1430.     { rows }
  1431.     MoveTo(0, 35);
  1432.     Line(kRowTitleWidth - 1, 0);
  1433.  
  1434.     MoveTo(0, 35 + kCellHeight - 1);
  1435.     Line(kRowTitleWidth - 1, 0);
  1436.  
  1437.     { columns }
  1438.     MoveTo(kRowTitleWidth - 1, 35);
  1439.     Line(0, kCellHeight - 1);
  1440.  
  1441.     INHERITED Draw(area);
  1442.     END;
  1443.  
  1444. {***************************************************************************************************
  1445.     T C e l l s V i e w
  1446. ***************************************************************************************************}
  1447. {$S AOpen}
  1448.  
  1449. PROCEDURE TCellsView.ICellsView(itsDocument: TCalcDocument;
  1450.                                 forClipboard: BOOLEAN;
  1451.                                 itsParent: TView);
  1452.  
  1453.     BEGIN
  1454.     fCalcDocument := itsDocument;
  1455.     fLastOptionKey := FALSE;                            { Used for DoSetCursor to the grabber hand }
  1456.  
  1457.     ITextGridView(itsDocument, itsParent, gZeroVPt, gZeroVPt, sizeVariable, sizeVariable,
  1458.                   itsDocument.fNoOfRows, itsDocument.fNoOfColumns, 0, kCellWidth, kAdorn, kAdorn,
  1459.                   0, 0, FALSE, gSystemStyle);
  1460.     fIdleFreq := Max(GetCaretTime DIV 2, 1);            { So we can trackCursor for the GrabberHand.
  1461.                                                          With MF 7.0 we could setup a VBL that
  1462.                                                          monitered the modifiers and called Wakeup
  1463.                                                          with our PID. Even better would be a call
  1464.                                                          that set the event manager so that an
  1465.                                                          event could be returned on modifier key
  1466.                                                          changes… oh, well. }
  1467.     END;
  1468.  
  1469. {--------------------------------------------------------------------------------------------------}
  1470. {$S AOpen}
  1471.  
  1472. PROCEDURE TCellsView.IRes(itsDocument: TDocument;
  1473.                           itsSuperView: TView;
  1474.                           VAR itsParams: Ptr); OVERRIDE;
  1475.  
  1476.     BEGIN
  1477.     fCalcDocument := TCalcDocument(itsDocument);
  1478.     INHERITED IRes(itsDocument, itsSuperView, itsParams);
  1479.     fIdleFreq := Max(GetCaretTime DIV 2, 1);            { So we can trackCursor for the GrabberHand.
  1480.                                                          With MF 7.0 we could setup a VBL that
  1481.                                                          monitered the modifiers and called Wakeup
  1482.                                                          with our PID. Even better would be a call
  1483.                                                          that set the event manager so that an
  1484.                                                          event could be returned on modifier key
  1485.                                                          changes… oh, well. }
  1486.     END;
  1487.  
  1488. {--------------------------------------------------------------------------------------------------}
  1489. {$S ARes}
  1490.  
  1491. PROCEDURE TCellsView.AdornRow(aRow: INTEGER;
  1492.                               area: Rect); OVERRIDE;
  1493.  
  1494.     BEGIN
  1495.     PenPat(gRowSeparatorPattern);
  1496.     PenSize(1, 1);
  1497.  
  1498.     MoveTo(area.left, area.bottom - 1);
  1499.     LineTo(area.right - 1, area.bottom - 1);
  1500.     END;
  1501.  
  1502. {--------------------------------------------------------------------------------------------------}
  1503. {$S ARes}
  1504.  
  1505. PROCEDURE TCellsView.AdornCol(aCol: INTEGER;
  1506.                               area: Rect); OVERRIDE;
  1507.  
  1508.     BEGIN
  1509.     PenPat(gColumnSeparatorPattern);
  1510.     PenSize(1, 1);
  1511.  
  1512.     MoveTo(area.right - 1, area.top);
  1513.     LineTo(area.right - 1, area.bottom - 1);
  1514.     END;
  1515.  
  1516. {--------------------------------------------------------------------------------------------------}
  1517. {$S AClipBoard}
  1518.  
  1519. FUNCTION TCellsView.ContainsClipType(aType: ResType): BOOLEAN;
  1520.  
  1521.     BEGIN
  1522.     ContainsClipType := aType = kCalcScrapType;
  1523.     END;
  1524.  
  1525. {--------------------------------------------------------------------------------------------------}
  1526. {$S ARes}
  1527.  
  1528. FUNCTION TCellsView.DoIdle(phase: IdlePhase): BOOLEAN;
  1529.  
  1530.     CONST
  1531.         kOptionKey            = $3A;
  1532.  
  1533.     VAR
  1534.         aKeyMap:            KeyMap;
  1535.  
  1536.     BEGIN
  1537.     DoIdle := FALSE;                                    { Didn't free myself }
  1538.  
  1539.     GetKeys(aKeyMap);
  1540.     IF fLastOptionKey <> aKeyMap[kOptionKey] THEN
  1541.         BEGIN
  1542.         fLastOptionKey := aKeyMap[kOptionKey];
  1543.         gApplication.InvalidateCursorRgn;                { Since we track the option key, we now need
  1544.                                                          to recalculate cursor rgn and SET the
  1545.                                                          cursor at next opportunity }
  1546.         END;
  1547.  
  1548.     END;
  1549.  
  1550. {--------------------------------------------------------------------------------------------------}
  1551. {$S ARes}
  1552.  
  1553. FUNCTION TCellsView.DoKeyCommand(Ch: CHAR;
  1554.                                  aKeyCode: INTEGER;
  1555.                                  VAR info: EventInfo): TCommand;
  1556.  { This view only handles arrow keys, tab, return and enter.  It assumes
  1557.    the other keys are handled by the entry view object. }
  1558.  
  1559.     VAR
  1560.         r:                    RowNumber;
  1561.         c:                    ColumnNumber;
  1562.         aCell:                GridCell;
  1563.         minToSee:            Point;
  1564.         aRect:                VRect;
  1565.  
  1566.     BEGIN
  1567.     DoKeyCommand := NIL;
  1568.  
  1569.     c := fCalcDocument.fEditColumn;
  1570.     r := fCalcDocument.fEditRow;
  1571.  
  1572.     CASE Ch OF
  1573.         chEnter:
  1574.             BEGIN
  1575.             { Stay on same cell }
  1576.             END;
  1577.         chTab, chRight:
  1578.             c := Min(c + 1, fCalcDocument.fNoOfColumns);
  1579.         chLeft:
  1580.             c := Max(c - 1, 1);
  1581.         chUp:
  1582.             r := Max(r - 1, 1);
  1583.         chReturn, chDown:
  1584.             r := Min(r + 1, fCalcDocument.fNoOfRows);
  1585.         OTHERWISE
  1586.             BEGIN
  1587.             DoKeyCommand := INHERITED DoKeyCommand(Ch, aKeyCode, info);
  1588.             fCalcDocument.fEditCell := fCalcDocument.GetCell(r, c);
  1589.             EXIT(DoKeyCommand);
  1590.             END;
  1591.     END;
  1592.  
  1593.     aCell.h := c;
  1594.     aCell.v := r;
  1595.  
  1596.     WITH fCalcDocument DO
  1597.         BEGIN
  1598.         SetChangeCount(Max(fChangeCount + 1, 1));        { enable Save - document may have changed }
  1599.  
  1600.         fEntryView.EditMode(FALSE);
  1601.         fColumnsView.SetEmptySelection(kHighlight);
  1602.         fRowsView.SetEmptySelection(kHighlight);
  1603.         fColumnIsSelected := FALSE;
  1604.  
  1605.         SelectCell(aCell, kDontExtend, kHighlight, kSelect);
  1606.         IF fEntryView.fTouched THEN
  1607.             DoRecalculate(NOT kForceAutomatic, kSetDependents);
  1608.         ScrollSelectionIntoView(TRUE);
  1609.  
  1610.         { fix the columns view }
  1611.         minToSee.h := fColumnsView.GetColWidth(aCell.h);
  1612.         minToSee.v := kCellHeight;
  1613.         aCell.v := 1;
  1614.         fColumnsView.CellToVRect(aCell, aRect);
  1615.         fColumnsView.RevealRect(aRect, minToSee, TRUE);
  1616.  
  1617.         { fix the rows view }
  1618.         minToSee.h := kCellWidth;
  1619.         minToSee.v := kCellHeight;
  1620.         aCell.v := r;
  1621.         aCell.h := 1;
  1622.         fRowsView.CellToVRect(aCell, aRect);
  1623.         fRowsView.RevealRect(aRect, minToSee, TRUE);
  1624.         END;
  1625.     END;
  1626.  
  1627. {--------------------------------------------------------------------------------------------------}
  1628. {$S ASelCommand}
  1629.  
  1630. FUNCTION TCellsView.DoMenuCommand(aCmdNumber: cmdNumber): TCommand; OVERRIDE;
  1631.  
  1632.     VAR
  1633.         aCellEditCommand:    TCellEditCommand;
  1634.         aCellPasteCommand:    TCellPasteCommand;
  1635.         cellsToSelect:        RgnHandle;
  1636.         aRect:                Rect;
  1637.  
  1638.     BEGIN
  1639.     CASE aCmdNumber OF
  1640.         cSelectAll:
  1641.             BEGIN
  1642.             aRect := fCalcDocument.fInUseBounds;
  1643.             WITH aRect DO
  1644.                 BEGIN
  1645.                 right := right + 1;
  1646.                 bottom := bottom + 1;
  1647.                 END;
  1648.             cellsToSelect := MakeNewRgn;
  1649.             RectRgn(cellsToSelect, aRect);
  1650.             SetSelection(cellsToSelect, kDontExtend, kHighlight, kSelect);
  1651.             DisposeRgn(cellsToSelect);
  1652.             WITH fCalcDocument DO
  1653.                 BEGIN
  1654.                 fSelectionType := AllSelection;
  1655.                 fRowsView.SetEmptySelection(kHighlight);
  1656.                 fColumnsView.SetEmptySelection(kHighlight);
  1657.                 fColumnIsSelected := FALSE;
  1658.                 END;
  1659.             DoMenuCommand := NIL;
  1660.             END;
  1661.  
  1662.         cCut, cCopy, cClear:
  1663.         { If user isn't editing this cell, he must want the cell itself. }
  1664.             IF NOT fCalcDocument.fEntryView.fTEditing THEN
  1665.                 BEGIN
  1666.                 NEW(aCellEditCommand);
  1667.                 FailNIL(aCellEditCommand);
  1668.                 aCellEditCommand.ICellEditCommand(fCalcDocument, aCmdNumber);
  1669.                 DoMenuCommand := aCellEditCommand;
  1670.                 END
  1671.             ELSE
  1672.                 BEGIN                                    { get ready for TextEdit operation }
  1673.                 WITH fCalcDocument DO
  1674.                     fEditCell := GetCell(fEditRow, fEditColumn);
  1675.                 DoMenuCommand := INHERITED DoMenuCommand(aCmdNumber);
  1676.                 END;
  1677.  
  1678.         cPaste:
  1679.             IF gClipView.ContainsClipType(kCalcScrapType) THEN
  1680.                 BEGIN
  1681.                 NEW(aCellPasteCommand);
  1682.                 FailNIL(aCellPasteCommand);
  1683.                 aCellPasteCommand.ICellPasteCommand(fCalcDocument);
  1684.                 DoMenuCommand := aCellPasteCommand;
  1685.                 END
  1686.             ELSE
  1687.                 BEGIN                                    { paste text into entry view }
  1688.                 WITH fCalcDocument DO
  1689.                     BEGIN
  1690.                     fEditCell := GetCell(fEditRow, fEditColumn);
  1691.                     IF NOT fEntryView.fTEditing THEN
  1692.                         fEntryView.SetEditMode;         { prepare view for paste of text }
  1693.                     END;
  1694.                 DoMenuCommand := INHERITED DoMenuCommand(aCmdNumber);
  1695.                 END;
  1696.  
  1697.         OTHERWISE
  1698.             DoMenuCommand := INHERITED DoMenuCommand(aCmdNumber);
  1699.     END;
  1700.     END;
  1701.  
  1702. {--------------------------------------------------------------------------------------------------}
  1703. {$S ASelCommand}
  1704.  
  1705. FUNCTION TCellsView.DoMouseCommand(VAR theMouse: Point;
  1706.                                    VAR info: EventInfo;
  1707.                                    VAR hysteresis: Point): TCommand; OVERRIDE;
  1708.  
  1709.     VAR
  1710.         aCellSelector:        TCalcSelectCommand;
  1711.         aColumnSizer:        TColumnSizer;
  1712.         aCell:                GridCell;
  1713.         whichPart:            GridViewPart;
  1714.         aRow:                INTEGER;
  1715.         aCol:                INTEGER;
  1716.         aGrabber:            TGrabberTracker;
  1717.  
  1718.     BEGIN
  1719.     DoMouseCommand := NIL;
  1720.     whichPart := IdentifyPoint(theMouse, aRow, aCol);
  1721.     aCell.h := aCol;
  1722.     aCell.v := aRow;
  1723.  
  1724.     IF info.theOptionKey THEN
  1725.         BEGIN
  1726.         NEW(aGrabber);
  1727.         FailNIL(aGrabber);
  1728.         aGrabber.IGrabberTracker(cNoCommand, fCalcDocument, SELF, GetScroller(FALSE));
  1729.         DoMouseCommand := aGrabber;
  1730.         END
  1731.     ELSE
  1732.         BEGIN
  1733.         CASE whichPart OF
  1734.             inCell:
  1735.                 BEGIN
  1736.                 NEW(aCellSelector);
  1737.                 FailNIL(aCellSelector);
  1738.                 aCellSelector.ICalcSelectCommand(fCalcDocument, SELF, info.theShiftKey,
  1739.                                                  info.theCmdKey);
  1740.                 DoMouseCommand := aCellSelector;
  1741.                 fCalcDocument.fSelectionType := CellSelection;
  1742.                 END;
  1743.  
  1744.             inColumn, inVertex:
  1745.                 BEGIN
  1746.                 IF aCol > 1 THEN
  1747.                     BEGIN
  1748.                     NEW(aColumnSizer);
  1749.                     FailNIL(aColumnSizer);
  1750.                     aColumnSizer.IColumnSizer(fCalcDocument, aCol - 1);
  1751.                     DoMouseCommand := aColumnSizer;
  1752.                     END;
  1753.                 END;
  1754.  
  1755.             OTHERWISE;
  1756.         END;
  1757.         fCalcDocument.fColumnsView.SetEmptySelection(kHighlight);
  1758.         fCalcDocument.fRowsView.SetEmptySelection(kHighlight);
  1759.         fCalcDocument.fColumnIsSelected := FALSE;
  1760.         fCalcDocument.fEditCell := NIL;
  1761.         END;
  1762.     END;
  1763.  
  1764. {--------------------------------------------------------------------------------------------------}
  1765. {$S ARes}
  1766.  
  1767. FUNCTION TCellsView.DoSetCursor(localPoint: Point;
  1768.                                 cursorRgn: RgnHandle): BOOLEAN; OVERRIDE;
  1769.  
  1770.     CONST
  1771.         kOptionKey            = $3A;
  1772.  
  1773.     VAR
  1774.         aRow:                INTEGER;
  1775.         aCol:                INTEGER;
  1776.         aKeyMap:            KeyMap;
  1777.         cellsExtent:        VRect;
  1778.         cellsQDExtent, columnQDExtent: Rect;
  1779.  
  1780.     BEGIN
  1781.     DoSetCursor := FALSE;
  1782.  
  1783.     GetKeys(aKeyMap);
  1784.  
  1785.     { We may have been called from a mouse-moved.  Be kind to the DoIdle }
  1786.     fLastOptionKey := aKeyMap[kOptionKey];
  1787.  
  1788.     IF fLastOptionKey THEN
  1789.         BEGIN
  1790.         DoSetCursor := TRUE;
  1791.         SetCursor(GetCursor(kGrabberHand)^^);
  1792.         GetQDExtent(cellsQDExtent);
  1793.         RectRgn(cursorRgn, cellsQDExtent);
  1794.         END
  1795.     ELSE
  1796.         CASE IdentifyPoint(localPoint, aRow, aCol) OF
  1797.             badChoice: ;
  1798.             inColumn, inVertex:
  1799.                 IF aCol > 1 THEN
  1800.                     BEGIN
  1801.                     DoSetCursor := TRUE;
  1802.                     SetCursor(GetCursor(kColumnSizingCursor)^^);
  1803.                     ColToVRect(Min(aCol, fNumOfCols), 1, cellsExtent);
  1804.                     ViewToQDRect(cellsExtent, cellsQDExtent);
  1805.                     columnQDExtent := cellsQDExtent;
  1806.  
  1807.                     { Which edge is the mouse closer to? }
  1808.                     IF abs(columnQDExtent.right - localPoint.h) < abs(columnQDExtent.left -
  1809.                                                                       localPoint.h) THEN
  1810.                         columnQDExtent.left := columnQDExtent.right;
  1811.  
  1812.                     columnQDExtent.left := columnQDExtent.left - fColInset DIV 2;
  1813.                     columnQDExtent.right := columnQDExtent.left + fColInset;
  1814.                     RectRgn(cursorRgn, columnQDExtent);
  1815.                     END;
  1816.             inRow, inCell:
  1817.                 BEGIN
  1818.                 DoSetCursor := TRUE;
  1819.                 SetCursor(GetCursor(plusCursor)^^);
  1820.                 ColToVRect(Min(aCol, fNumOfCols), 1, cellsExtent);
  1821.                 InsetVRect(cellsExtent, fColInset DIV 2, 0); { Account for the column resizer }
  1822.                 ViewToQDRect(cellsExtent, cellsQDExtent);
  1823.                 RectRgn(cursorRgn, cellsQDExtent);
  1824.                 END;
  1825.         END;
  1826.     END;
  1827.  
  1828. {--------------------------------------------------------------------------------------------------}
  1829. {$S ARes}
  1830.  
  1831. PROCEDURE TCellsView.DoSetupMenus; OVERRIDE;
  1832.  
  1833.     VAR
  1834.         selection:            TypeOfSelection;
  1835.  
  1836.     BEGIN
  1837.     INHERITED DoSetupMenus;
  1838.  
  1839.     { If user isn't editing, then assume edit commands refer to cells }
  1840.     IF NOT fCalcDocument.fEntryView.fTEditing THEN
  1841.         BEGIN
  1842.         SetEditCmdName(cCut, cCutCells);
  1843.         SetEditCmdName(cCopy, cCopyCells);
  1844.         SetEditCmdName(cClear, cClearCells);
  1845.  
  1846.         CanPaste(kCalcScrapType);
  1847.         END;
  1848.  
  1849.     selection := fCalcDocument.fSelectionType;
  1850.     Enable(cCut, selection <> NoSelection);
  1851.     Enable(cCopy, selection <> NoSelection);
  1852.     Enable(cClear, selection <> NoSelection);
  1853.     Enable(cSelectAll, TRUE);
  1854.     END;
  1855.  
  1856. {--------------------------------------------------------------------------------------------------}
  1857. {$S ARes}
  1858.  
  1859. PROCEDURE TCellsView.DrawCell(aCell: GridCell;
  1860.                               aQDRect: Rect); OVERRIDE;
  1861.  
  1862.     VAR
  1863.         theCell:            TCell;
  1864.         theString:            Str255;
  1865.  
  1866.     BEGIN
  1867.     theCell := fCalcDocument.GetExistingCell(aCell.v, aCell.h);
  1868.     IF (theCell <> NIL) THEN
  1869.         WITH theCell DO
  1870.             BEGIN
  1871.             GetValueAsString(theString);
  1872.             SmartDrawString(theString, aQDRect,
  1873.                             fCalcDocument.GetColumn(aCell.h).fFormat.fJustification);
  1874.             END;
  1875.  
  1876.     END;
  1877.  
  1878. {--------------------------------------------------------------------------------------------------}
  1879. {$S AFields}
  1880.  
  1881. PROCEDURE TCellsView.Fields(PROCEDURE DoToField(fieldName: Str255;
  1882.                                                 fieldAddr: Ptr;
  1883.                                                 fieldType: INTEGER)); OVERRIDE;
  1884.  
  1885.     BEGIN
  1886.     DoToField('TCellsView', NIL, bClass);
  1887.     DoToField('fCalcDocument', @fCalcDocument, bObject);
  1888.     INHERITED Fields(DoToField);
  1889.     END;
  1890.  
  1891. {--------------------------------------------------------------------------------------------------}
  1892. {$S ADoCommand}
  1893.  
  1894. PROCEDURE TCellsView.GetVisibleCells(VAR visibleCells: Rect);
  1895.  
  1896.     VAR
  1897.         visibleRect:        Rect;
  1898.         visibleVRect:        VRect;
  1899.         topLeftVPoint:        VPoint;
  1900.  
  1901.     BEGIN
  1902.     IF Focus THEN;                                        { appease QDToViewRect }
  1903.     GetVisibleRect(visibleRect);
  1904.     topLeftVPoint := GetScroller(TRUE).fTranslation;
  1905.     visibleRect.topLeft := ViewToQDPt(topLeftVPoint);
  1906.     QDToViewRect(visibleRect, visibleVRect);
  1907.     visibleCells.topLeft := VPointToCell(visibleVRect.topLeft);
  1908.     visibleCells.botRight := VPointToCell(visibleVRect.botRight);
  1909.     END;
  1910.  
  1911. {--------------------------------------------------------------------------------------------------}
  1912. {$S ADoCommand}
  1913.  
  1914. FUNCTION TCellsView.IsCellVisible(aCell: GridCell): BOOLEAN;
  1915.  
  1916.     VAR
  1917.         visibleCells:        Rect;
  1918.  
  1919.     BEGIN
  1920.     GetVisibleCells(visibleCells);
  1921.     IsCellVisible := PtInRect(aCell, visibleCells);     { ??? use fCalcDocument.CellInRange }
  1922.     END;
  1923.  
  1924. {--------------------------------------------------------------------------------------------------}
  1925. {$S ADoCommand}
  1926.  
  1927. PROCEDURE TCellsView.PositionAtCell(aCell: GridCell);
  1928.  
  1929.     VAR
  1930.         aRect:                VRect;
  1931.         minToSee:            Point;
  1932.         r:                    INTEGER;
  1933.  
  1934.     BEGIN
  1935.     { position the cells view first }
  1936.     CellToVRect(aCell, aRect);
  1937.     WITH aRect DO
  1938.         SetPt(minToSee, right - left, bottom - top);
  1939.     RevealRect(aRect, minToSee, TRUE);
  1940.  
  1941.     WITH fCalcDocument DO
  1942.         BEGIN
  1943.         { fix up the columns view }
  1944.         r := aCell.v;
  1945.         minToSee.h := fColumnsView.GetColWidth(aCell.h);
  1946.         minToSee.v := kCellHeight;
  1947.         aCell.v := 1;
  1948.         fColumnsView.CellToVRect(aCell, aRect);
  1949.         fColumnsView.RevealRect(aRect, minToSee, TRUE);
  1950.  
  1951.         { fix up the rows view }
  1952.         minToSee.h := kCellWidth;
  1953.         minToSee.v := kCellHeight;
  1954.         aCell.v := r;
  1955.         aCell.h := 1;
  1956.         fRowsView.CellToVRect(aCell, aRect);
  1957.         fRowsView.RevealRect(aRect, minToSee, TRUE);
  1958.         END;
  1959.     END;
  1960.  
  1961. {--------------------------------------------------------------------------------------------------}
  1962. {$S ADoCommand}
  1963.  
  1964. PROCEDURE TCellsView.ReSelect(cellRegion: RgnHandle);
  1965.  
  1966.     VAR
  1967.         aCell:                GridCell;
  1968.  
  1969.     BEGIN
  1970.     aCell := cellRegion^^.rgnBBox.topLeft;
  1971.     IF NOT IsCellVisible(aCell) THEN
  1972.         PositionAtCell(aCell);                            { position cellRegion at top left of grid }
  1973.  
  1974.     IF NOT EqualRect(cellRegion^^.rgnBBox, fSelections^^.rgnBBox) THEN
  1975.         BEGIN
  1976.         WITH fCalcDocument DO
  1977.             BEGIN
  1978.             fColumnsView.SetEmptySelection(kHighlight);
  1979.             fRowsView.SetEmptySelection(kHighlight);
  1980.             fColumnIsSelected := FALSE;
  1981.             END;
  1982.         SetSelection(cellRegion, kDontExtend, kHighlight, kSelect);
  1983.         END;
  1984.     END;
  1985.  
  1986. {--------------------------------------------------------------------------------------------------}
  1987. {$S ADoCommand}
  1988.  
  1989. PROCEDURE TCellsView.ReSelectCell(aCell: GridCell);
  1990.  
  1991.     VAR
  1992.         cellRect:            Rect;
  1993.  
  1994.     BEGIN
  1995.     IF NOT IsCellVisible(aCell) THEN
  1996.         PositionAtCell(aCell);                            { position aCell at top left of grid }
  1997.  
  1998.     WITH aCell DO
  1999.         SetRect(cellRect, h, v, h + 1, v + 1);
  2000.     IF NOT EqualRect(cellRect, fSelections^^.rgnBBox) THEN
  2001.         BEGIN
  2002.         WITH fCalcDocument DO
  2003.             BEGIN
  2004.             fColumnsView.SetEmptySelection(kHighlight);
  2005.             fRowsView.SetEmptySelection(kHighlight);
  2006.             fColumnIsSelected := FALSE;
  2007.             END;
  2008.         SelectCell(aCell, kDontExtend, kHighlight, kSelect);
  2009.         END;
  2010.     END;
  2011.  
  2012. {--------------------------------------------------------------------------------------------------}
  2013. {$S ADoCommand}
  2014.  
  2015. PROCEDURE TCellsView.ScrollSelectionIntoView(redraw: BOOLEAN); OVERRIDE;
  2016.  
  2017.     VAR
  2018.         topLeftRect:        VRect;
  2019.         minToSee:            Point;
  2020.  
  2021.     BEGIN
  2022.     IF NOT (EmptyRgn(fSelections)) THEN
  2023.         BEGIN
  2024.         CellToVRect(fSelections^^.rgnBBox.topLeft, topLeftRect);
  2025.         WITH topLeftRect DO
  2026.             SetPt(minToSee, right - left, bottom - top);
  2027.         RevealRect(topLeftRect, minToSee, redraw);
  2028.         END;
  2029.     END;
  2030.  
  2031. {--------------------------------------------------------------------------------------------------}
  2032. {$S ADoCommand}
  2033.  
  2034. PROCEDURE TCellsView.SetCell(aCell: GridCell);
  2035.  
  2036.     BEGIN
  2037.     fCalcDocument.EditCell;                             { cell formula := string in entry view }
  2038.     InvalidateCell(aCell);                                { redraw the cell }
  2039.     END;
  2040.  
  2041. {--------------------------------------------------------------------------------------------------}
  2042. {$S ADoCommand}
  2043.  
  2044. PROCEDURE TCellsView.SetSelection(cellsToSelect: RgnHandle;
  2045.                                   extendSelection, highlight, select: BOOLEAN); OVERRIDE;
  2046.  
  2047.     VAR
  2048.         aQDRect:            Rect;
  2049.  
  2050.     BEGIN
  2051.     WITH fCalcDocument DO
  2052.         BEGIN
  2053.         INHERITED SetSelection(cellsToSelect, extendSelection, highlight, select);
  2054.  
  2055.         IF fEntryView.fTouched THEN                     { "commit" last cell }
  2056.             BEGIN
  2057.             EditCell;                                    { change fEditCell's formula to the string
  2058.                                                          in fEntryView }
  2059.             fEntryView.SetToString('');
  2060.             END;
  2061.  
  2062.         IF NOT extendSelection & (cellsToSelect^^.rgnBBox.top <> 0) &
  2063.            (cellsToSelect^^.rgnBBox.left <> 0) THEN
  2064.             BEGIN
  2065.             fEditColumn := cellsToSelect^^.rgnBBox.left;
  2066.             fEditRow := cellsToSelect^^.rgnBBox.top;
  2067.             fEditCell := fCells[fEditRow, fEditColumn];
  2068.  
  2069.             IF fCoordView.Focus THEN
  2070.                 BEGIN
  2071.                 fCoordView.GetQDExtent(aQDRect);
  2072.                 fCoordView.InvalidRect(aQDRect);
  2073.                 END;
  2074.             END;
  2075.  
  2076.         SetEntry(fEditRow, fEditColumn);                { set entry view contents to new cell }
  2077.         END;
  2078.     END;
  2079.  
  2080. {--------------------------------------------------------------------------------------------------}
  2081. {$S AClipBoard}
  2082.  
  2083. PROCEDURE TCellsView.WriteCalcScrap(calcScrap: Handle);
  2084.  
  2085.     VAR
  2086.         scrapOffset:        LONGINT;
  2087.         scrapInfo:            ScrapInfoRecord;
  2088.         cellsWritten:        INTEGER;
  2089.         i:                    INTEGER;
  2090.         r:                    Rect;
  2091.  
  2092. {--------------------------------------------------------------------------------------------------}
  2093.  
  2094.     PROCEDURE WriteCellToScrap(aCell: GridCell);
  2095.  
  2096.         BEGIN
  2097.         WITH fCalcDocument.GetCell(aCell.v, aCell.h) DO
  2098.             WriteToScrap(calcScrap, scrapOffset);
  2099.         cellsWritten := cellsWritten + 1;
  2100.         END;
  2101.  
  2102.     BEGIN
  2103.     SetHandleSize(calcScrap, 0);
  2104.     scrapOffset := 0;
  2105.  
  2106.     scrapInfo.selection.top := 1;
  2107.     scrapInfo.selection.left := 1;
  2108.     scrapInfo.selection.bottom := fCalcDocument.fNoOfRows;
  2109.     scrapInfo.selection.right := fCalcDocument.fNoOfColumns;
  2110.     scrapInfo.noOfCells := fCalcDocument.fAllocatedCells;
  2111.     WriteScrap(calcScrap, scrapOffset, @scrapInfo, SIZEOF(scrapInfo));
  2112.  
  2113.     cellsWritten := 0;
  2114.     WITH fCalcDocument DO
  2115.         BEGIN
  2116.         FOR i := 1 TO fCalcDocument.fNoOfRows DO
  2117.             BEGIN
  2118.             WITH fCalcDocument.GetRow(i) DO
  2119.                 WriteToScrap(calcScrap, scrapOffset);
  2120.             END;
  2121.  
  2122.         FOR i := 1 TO fCalcDocument.fNoOfColumns DO
  2123.             BEGIN
  2124.             WITH fCalcDocument.GetColumn(i) DO
  2125.                 WriteToScrap(calcScrap, scrapOffset);
  2126.             END;
  2127.         r := fCalcDocument.fInUseBounds;
  2128.         EachExistingCellDo(r, WriteCellToScrap);
  2129.         END;
  2130.  
  2131.     {$IFC qDebug}
  2132.     WRITELN('WriteCalcScrap: Number of cells written: ', cellsWritten: 0);
  2133.     IF cellsWritten <> scrapInfo.noOfCells THEN
  2134.         BEGIN
  2135.         WRITELN('WriteCalcScrap: Incorrect number of cells written.');
  2136.         WRITELN('     Should be ', scrapInfo.noOfCells: 0, ', was ', cellsWritten: 0);
  2137.         ProgramBreak('');
  2138.         END;
  2139.     {$ENDC}
  2140.  
  2141.     END;
  2142.  
  2143. {--------------------------------------------------------------------------------------------------}
  2144. {$S AClipBoard}
  2145.  
  2146. PROCEDURE TCellsView.WriteTextScrap(textScrap: Handle);
  2147.  
  2148.     VAR
  2149.         r:                    RowNumber;
  2150.         c:                    ColumnNumber;
  2151.         theText:            Str255;
  2152.         scrapOffset:        LONGINT;
  2153.         savedPort:            GrafPtr;
  2154.  
  2155.     BEGIN
  2156.     GetPort(savedPort);                                 { Use work port because GetValueAsString }
  2157.     SetPort(gWorkPort);                                 { …sets the current port's font }
  2158.  
  2159.     SetHandleSize(textScrap, 0);
  2160.     scrapOffset := 0;
  2161.  
  2162.     FOR r := 1 TO fCalcDocument.fNoOfRows DO
  2163.         BEGIN
  2164.         FOR c := 1 TO fCalcDocument.fNoOfColumns DO
  2165.             BEGIN
  2166.             IF fCalcDocument.CellExists(r, c) THEN
  2167.                 fCalcDocument.GetCell(r, c).GetValueAsString(theText)
  2168.             ELSE
  2169.                 theText := '';
  2170.             IF c > 1 THEN
  2171.                 theText := CONCAT(chTab, theText);
  2172.             WriteScrap(textScrap, scrapOffset, POINTER(ORD4(@theText) + 1), LENGTH(theText));
  2173.             END;
  2174.         theText := chReturn;
  2175.         WriteScrap(textScrap, scrapOffset, POINTER(ORD4(@theText) + 1), LENGTH(theText));
  2176.         END;
  2177.  
  2178.     SetPort(savedPort);
  2179.     END;
  2180.  
  2181. {--------------------------------------------------------------------------------------------------}
  2182. {$S AClipBoard}
  2183.  
  2184. PROCEDURE TCellsView.WriteToDeskScrap; OVERRIDE;
  2185.  
  2186.     VAR
  2187.         textScrap:            Handle;
  2188.         calcScrap:            Handle;
  2189.         err:                OSErr;
  2190.  
  2191.     BEGIN
  2192.     textScrap := NewPermHandle(0);
  2193.     FailNIL(textScrap);
  2194.     WriteTextScrap(textScrap);
  2195.     err := PutDeskScrapData(kTextScrapType, textScrap);
  2196.     textScrap := DisposeIfHandle(textScrap);
  2197.  
  2198.     FailOSErr(err);
  2199.  
  2200.     calcScrap := NewPermHandle(0);
  2201.     FailNIL(calcScrap);
  2202.     WriteCalcScrap(calcScrap);
  2203.     err := PutDeskScrapData(kCalcScrapType, calcScrap);
  2204.     calcScrap := DisposeIfHandle(calcScrap);
  2205.  
  2206.     FailOSErr(err);
  2207.     END;
  2208.  
  2209. {--------------------------------------------------------------------------------------------------}
  2210. {$S ANonRes}
  2211.  
  2212. FUNCTION TCellsView.DoBreakFollowing(vhs: VHSelect;
  2213.                                      prevBreak: VCoordinate;
  2214.                                      VAR Automatic: BOOLEAN): VCoordinate; OVERRIDE;
  2215. { Determines where page breaks occur for printing. }
  2216.  
  2217.     VAR
  2218.         thisBreak:            VCoordinate;
  2219.         rowsPerPage:        INTEGER;
  2220.         totalWidth:         INTEGER;
  2221.         width:                INTEGER;
  2222.         pageWidth:            INTEGER;
  2223.         extentRect:         VRect;
  2224.         firstCol:            ColumnNumber;
  2225.         c:                    ColumnNumber;
  2226.  
  2227.     FUNCTION ColumnAtCoord(loc: VCoordinate): INTEGER;
  2228.  
  2229.         BEGIN
  2230.         ColumnAtCoord := 1;
  2231.         IF loc = 0 THEN
  2232.             EXIT(ColumnAtCoord);
  2233.  
  2234.         c := 0;
  2235.         width := 0;
  2236.         REPEAT
  2237.             c := c + 1;
  2238.             width := width + GetColWidth(c);
  2239.         UNTIL width >= loc;
  2240.         ColumnAtCoord := c + 1;
  2241.         END;
  2242.  
  2243.     BEGIN
  2244.     GetExtent(extentRect);
  2245.     CASE vhs OF
  2246.         h:
  2247.             BEGIN
  2248.             rowsPerPage := fPrintHandler.fViewPerPage.v DIV kCellHeight;
  2249.             thisBreak := prevBreak + (rowsPerPage * kCellHeight);
  2250.             END;
  2251.         v:
  2252.             BEGIN
  2253.             pageWidth := fPrintHandler.fViewPerPage.h;
  2254.             totalWidth := 0;
  2255.             firstCol := ColumnAtCoord(prevBreak);
  2256.             FOR c := firstCol TO fCalcDocument.fNoOfColumns DO
  2257.                 BEGIN
  2258.                 width := GetColWidth(c);
  2259.                 IF totalWidth + width <= pageWidth THEN
  2260.                     totalWidth := totalWidth + width
  2261.                 ELSE
  2262.                     BEGIN
  2263.                     thisBreak := prevBreak + totalWidth;
  2264.                     LEAVE;
  2265.                     END;
  2266.                 END;
  2267.             IF thisBreak = prevBreak THEN                { Prevent ∞ loop resizing a far-right column
  2268.                                                          (L.T.!) }
  2269.                 thisBreak := extentRect.right;
  2270.             END;
  2271.     END;
  2272.     thisBreak := Min(thisBreak, extentRect.botRight.vh[gOrthogonal[vhs]]);
  2273.  
  2274.     {$IFC qDebug}
  2275.     IF (thisBreak <= prevBreak) | gDebugPrinting THEN
  2276.         BEGIN
  2277.         WRITE('TCellsView.DoBreakFollowing: prevBreak=');
  2278.         IF vhs = v THEN
  2279.             WRITELN('[v]', prevBreak, ', thisBreak=[v]', thisBreak)
  2280.         ELSE
  2281.             WRITELN('[h]', prevBreak, ', thisBreak=[h]', thisBreak);
  2282.  
  2283.         IF thisBreak <= prevBreak THEN
  2284.             ProgramBreak('thisBreak <= prevBreak');
  2285.         END;
  2286.     {$ENDC}
  2287.  
  2288.     DoBreakFollowing := thisBreak;
  2289.     END;
  2290.  
  2291. {--------------------------------------------------------------------------------------------------}
  2292. {$IFC qDebug}
  2293. {$S ANonRes}
  2294.  
  2295. PROCEDURE TCellsView.DoDrawPageBreak(vhs: VHSelect;
  2296.                                      whichBreak: INTEGER;
  2297.                                      loc: VCoordinate;
  2298.                                      Automatic: BOOLEAN); OVERRIDE;
  2299.  
  2300.     VAR
  2301.         vPt:                VPoint;
  2302.         qdStartPt:            Point;
  2303.         qdEndPt:            Point;
  2304.  
  2305.     BEGIN
  2306.     IF gDebugPrinting THEN
  2307.         BEGIN
  2308.         vPt.vh[gOrthogonal[vhs]] := loc;
  2309.         vPt.vh[vhs] := 0;
  2310.         qdStartPt := ViewToQDPt(vPt);
  2311.         vPt.vh[vhs] := fSize.vh[vhs] - gBreaksPenState.pnSize.vh[vhs];
  2312.         qdEndPt := ViewToQDPt(vPt);
  2313.  
  2314.         MoveTo(qdStartPt.h, qdStartPt.v);
  2315.         LineTo(qdEndPt.h, qdEndPt.v);
  2316.         END;
  2317.     END;
  2318. {$ENDC}
  2319.  
  2320. {--------------------------------------------------------------------------------------------------}
  2321. {$S ANonRes}
  2322.  
  2323. PROCEDURE TCellsView.GetPrintExtent(VAR printExtent: VRect); OVERRIDE;
  2324. { Overridden to provide for Print Selection command. }
  2325.  
  2326.     VAR
  2327.         aRect:                VRect;
  2328.         tlCell:             GridCell;
  2329.         brCell:             GridCell;
  2330.  
  2331.     BEGIN
  2332.     IF TCalcPrintHandler(fPrintHandler).fCmdNumber = cPrintSelection THEN
  2333.         BEGIN
  2334.         tlCell := fSelections^^.rgnBBox.topLeft;
  2335.         brCell := fSelections^^.rgnBBox.botRight;
  2336.         brCell.h := Min(brCell.h - 1, fCalcDocument.fInUseBounds.right);
  2337.         brCell.v := Min(brCell.v - 1, fCalcDocument.fInUseBounds.bottom);
  2338.         END
  2339.     ELSE
  2340.         BEGIN
  2341.         tlCell := fCalcDocument.fInUseBounds.topLeft;
  2342.         brCell := fCalcDocument.fInUseBounds.botRight;
  2343.         END;
  2344.  
  2345.     CellToVRect(tlCell, aRect);
  2346.     printExtent.topLeft := aRect.topLeft;
  2347.     CellToVRect(brCell, aRect);
  2348.     printExtent.botRight := aRect.botRight;
  2349.  
  2350.     {$IFC qDebug}
  2351.     IF gDebugPrinting THEN
  2352.         BEGIN
  2353.         WrLblVRect('printExtent ', printExtent);
  2354.         WRITELN;
  2355.         END;
  2356.     {$ENDC}
  2357.     END;
  2358.  
  2359. {***************************************************************************************************
  2360.     T R o w s V i e w
  2361. ***************************************************************************************************}
  2362. {$S AOpen}
  2363.  
  2364. PROCEDURE TRowsView.IRes(itsDocument: TDocument;
  2365.                          itsSuperView: TView;
  2366.                          VAR itsParams: Ptr); OVERRIDE;
  2367.  
  2368.     BEGIN
  2369.     fCalcDocument := TCalcDocument(itsDocument);
  2370.     INHERITED IRes(itsDocument, itsSuperView, itsParams);
  2371.     END;
  2372.  
  2373. {--------------------------------------------------------------------------------------------------}
  2374. {$S ARes}
  2375.  
  2376. PROCEDURE TRowsView.AdornRow(aRow: INTEGER;
  2377.                              area: Rect); OVERRIDE;
  2378.  
  2379.     BEGIN
  2380.     PenSize(1, 1);
  2381.     PenPat(black);
  2382.  
  2383.     { right line }
  2384.     MoveTo(area.right - 1, area.top);
  2385.     LineTo(area.right - 1, area.bottom - 1);
  2386.  
  2387.     { bottom line }
  2388.     MoveTo(area.left, area.bottom - 1);
  2389.     LineTo(area.right - 1, area.bottom - 1);
  2390.     END;
  2391.  
  2392. {--------------------------------------------------------------------------------------------------}
  2393. {$S ASelCommand}
  2394.  
  2395. FUNCTION TRowsView.DoMouseCommand(VAR theMouse: Point;
  2396.                                   VAR info: EventInfo;
  2397.                                   VAR hysteresis: Point): TCommand; OVERRIDE;
  2398.  
  2399.     VAR
  2400.         aRowSelector:        TRowSelector;
  2401.  
  2402.     BEGIN
  2403.     NEW(aRowSelector);
  2404.     FailNIL(aRowSelector);
  2405.     aRowSelector.IRowSelector(fCalcDocument, SELF, info.theShiftKey, info.theCmdKey);
  2406.     DoMouseCommand := aRowSelector;
  2407.     WITH fCalcDocument DO
  2408.         BEGIN
  2409.         fSelectionType := RowSelection;
  2410.         fColumnsView.SetEmptySelection(kHighlight);
  2411.         fColumnIsSelected := FALSE;
  2412.         END;
  2413.     END;
  2414.  
  2415. {--------------------------------------------------------------------------------------------------}
  2416. {$S ARes}
  2417.  
  2418. FUNCTION TRowsView.DoSetCursor(localPoint: Point;
  2419.                                cursorRgn: RgnHandle): BOOLEAN; OVERRIDE;
  2420.  
  2421.     BEGIN
  2422.     DoSetCursor := FALSE;
  2423.     END;
  2424.  
  2425. {--------------------------------------------------------------------------------------------------}
  2426. {$S ARes}
  2427.  
  2428. PROCEDURE TRowsView.DrawCell(aCell: GridCell;
  2429.                              aQDRect: Rect); OVERRIDE;
  2430.  
  2431.     VAR
  2432.         theString:            Str255;
  2433.  
  2434.     BEGIN
  2435.     NumToString(aCell.v, theString);
  2436.     WITH aQDRect DO                                        { aesthetic adjustment of the rect }
  2437.         top := top + 2;
  2438.     MADrawString(@theString, aQDRect, teJustCenter);
  2439.     END;
  2440.  
  2441. {--------------------------------------------------------------------------------------------------}
  2442. {$S AFields}
  2443.  
  2444. PROCEDURE TRowsView.Fields(PROCEDURE DoToField(fieldName: Str255;
  2445.                                                fieldAddr: Ptr;
  2446.                                                fieldType: INTEGER)); OVERRIDE;
  2447.  
  2448.     BEGIN
  2449.     DoToField('TRowsView', NIL, bClass);
  2450.     DoToField('fCalcDocument', @fCalcDocument, bObject);
  2451.     INHERITED Fields(DoToField);
  2452.     END;
  2453.  
  2454. {***************************************************************************************************
  2455.     T C o l u m n s V i e w
  2456. ***************************************************************************************************}
  2457. {$S AOpen}
  2458.  
  2459. PROCEDURE TColumnsView.IRes(itsDocument: TDocument;
  2460.                             itsSuperView: TView;
  2461.                             VAR itsParams: Ptr); OVERRIDE;
  2462.  
  2463.     BEGIN
  2464.     fCalcDocument := TCalcDocument(itsDocument);
  2465.     INHERITED IRes(itsDocument, itsSuperView, itsParams);
  2466.     SetRowHeight(1, fNumOfRows, kCellHeight);
  2467.     fCalcDocument.fColumnIsSelected := FALSE;
  2468.     END;
  2469.  
  2470. {--------------------------------------------------------------------------------------------------}
  2471. {$S ARes}
  2472.  
  2473. PROCEDURE TColumnsView.AdornCol(aCol: INTEGER;
  2474.                                 area: Rect); OVERRIDE;
  2475.  
  2476.     BEGIN
  2477.     PenPat(black);
  2478.     PenSize(1, 1);
  2479.  
  2480.     { top line }
  2481.     MoveTo(area.left, area.top);
  2482.     LineTo(area.right - 1, area.top);
  2483.  
  2484.     { bottom line }
  2485.     MoveTo(area.left, area.bottom - 1);
  2486.     LineTo(area.right - 1, area.bottom - 1);
  2487.  
  2488.     { right line }
  2489.     MoveTo(area.right - 1, area.top);
  2490.     LineTo(area.right - 1, area.bottom - 1);
  2491.  
  2492.     END;
  2493.  
  2494. {--------------------------------------------------------------------------------------------------}
  2495. {$S ARes}
  2496.  
  2497. PROCEDURE TColumnsView.CoordToString(coord: INTEGER;
  2498.                                      VAR theString: Str255);
  2499.  
  2500.     BEGIN
  2501.     coord := coord - 1;
  2502.     IF coord < 26 THEN
  2503.         BEGIN
  2504.         theString := ' ';
  2505.         theString[1] := CHR(ORD('A') + coord);
  2506.         END
  2507.     ELSE
  2508.         BEGIN
  2509.         theString := '  ';
  2510.         theString[1] := CHR(ORD('A') + (coord DIV 26) - 1);
  2511.         theString[2] := CHR(ORD('A') + (coord MOD 26));
  2512.         END;
  2513.     END;
  2514.  
  2515. {--------------------------------------------------------------------------------------------------}
  2516. {$S ASelCommand}
  2517.  
  2518. FUNCTION TColumnsView.DoMouseCommand(VAR theMouse: Point;
  2519.                                      VAR info: EventInfo;
  2520.                                      VAR hysteresis: Point): TCommand; OVERRIDE;
  2521.  
  2522.     VAR
  2523.         aColumnSelector:    TColumnSelector;
  2524.         aColumnSizer:        TColumnSizer;
  2525.         aRow:                INTEGER;
  2526.         aCol:                INTEGER;
  2527.         whichPart:            GridViewPart;
  2528.         aCell:                GridCell;
  2529.  
  2530.     BEGIN
  2531.     DoMouseCommand := NIL;
  2532.     whichPart := IdentifyPoint(theMouse, aRow, aCol);
  2533.     aCell.h := aCol;
  2534.     aCell.v := aRow;
  2535.  
  2536.     CASE whichPart OF
  2537.         inCell:
  2538.             BEGIN
  2539.             fCalcDocument.fColumnIsSelected := TRUE;
  2540.             NEW(aColumnSelector);
  2541.             FailNIL(aColumnSelector);
  2542.             aColumnSelector.IColumnSelector(fCalcDocument, SELF, info.theShiftKey, info.theCmdKey);
  2543.             DoMouseCommand := aColumnSelector;
  2544.             fCalcDocument.fSelectionType := ColumnSelection;
  2545.             END;
  2546.  
  2547.         inColumn, inVertex:
  2548.             BEGIN
  2549.             IF aCol > 1 THEN
  2550.                 BEGIN
  2551.                 NEW(aColumnSizer);
  2552.                 FailNIL(aColumnSizer);
  2553.                 aColumnSizer.IColumnSizer(fCalcDocument, aCol - 1);
  2554.                 DoMouseCommand := aColumnSizer;
  2555.                 END;
  2556.             END;
  2557.  
  2558.         OTHERWISE;
  2559.     END;
  2560.     fCalcDocument.fRowsView.SetEmptySelection(kHighlight);
  2561.     END;
  2562.  
  2563. {--------------------------------------------------------------------------------------------------}
  2564. {$S ARes}
  2565.  
  2566. FUNCTION TColumnsView.DoSetCursor(localPoint: Point;
  2567.                                   cursorRgn: RgnHandle): BOOLEAN; OVERRIDE;
  2568.  
  2569.     VAR
  2570.         aRow:                INTEGER;
  2571.         aCol:                INTEGER;
  2572.         cellsExtent:        VRect;
  2573.         cellsQDExtent, columnQDExtent: Rect;
  2574.  
  2575.     BEGIN
  2576.     DoSetCursor := FALSE;
  2577.  
  2578.     CASE IdentifyPoint(localPoint, aRow, aCol) OF
  2579.         badChoice: ;
  2580.         inColumn, inVertex:
  2581.             IF aCol > 1 THEN
  2582.                 BEGIN
  2583.                 DoSetCursor := TRUE;
  2584.                 SetCursor(GetCursor(kColumnSizingCursor)^^);
  2585.                 ColToVRect(Min(aCol, fNumOfCols), 1, cellsExtent);
  2586.                 ViewToQDRect(cellsExtent, cellsQDExtent);
  2587.                 columnQDExtent := cellsQDExtent;
  2588.  
  2589.                 { Which edge is the mouse closer to? }
  2590.                 IF abs(columnQDExtent.right - localPoint.h) < abs(columnQDExtent.left -
  2591.                                                                   localPoint.h) THEN
  2592.                     columnQDExtent.left := columnQDExtent.right;
  2593.  
  2594.                 columnQDExtent.left := columnQDExtent.left - fColInset DIV 2;
  2595.                 columnQDExtent.right := columnQDExtent.left + fColInset;
  2596.                 RectRgn(cursorRgn, columnQDExtent);
  2597.                 END;
  2598.         inRow, inCell:
  2599.             BEGIN
  2600.             DoSetCursor := TRUE;
  2601.             SetCursor(arrow);
  2602.             ColToVRect(Min(aCol, fNumOfCols), 1, cellsExtent);
  2603.             InsetVRect(cellsExtent, fColInset DIV 2, 0); { Account for the column resizer }
  2604.             ViewToQDRect(cellsExtent, cellsQDExtent);
  2605.             RectRgn(cursorRgn, cellsQDExtent);
  2606.             END;
  2607.     END;
  2608.     END;
  2609.  
  2610. {--------------------------------------------------------------------------------------------------}
  2611. {$S ARes}
  2612.  
  2613. PROCEDURE TColumnsView.DrawCell(aCell: GridCell;
  2614.                                 aQDRect: Rect); OVERRIDE;
  2615.  
  2616.     VAR
  2617.         theString:            Str255;
  2618.  
  2619.     BEGIN
  2620.     CoordToString(aCell.h, theString);
  2621.     WITH aQDRect DO                                        { aesthetic adjustment of the rect }
  2622.         top := top + 2;
  2623.     MADrawString(@theString, aQDRect, teJustCenter);
  2624.     END;
  2625.  
  2626. {--------------------------------------------------------------------------------------------------}
  2627. {$S ADoCommand}
  2628.  
  2629. PROCEDURE TColumnsView.ReSelect(cellRegion: RgnHandle);
  2630.  
  2631.     VAR
  2632.         aCell:                GridCell;
  2633.         cellsInColumn:        RgnHandle;
  2634.         cellsToSelect:        RgnHandle;
  2635.  
  2636. {--------------------------------------------------------------------------------------------------}
  2637.  
  2638.     PROCEDURE GetColumnCells(columnCell: GridCell);
  2639.  
  2640.         VAR
  2641.             aRect:                Rect;
  2642.  
  2643.         BEGIN
  2644.         SetRect(aRect, columnCell.h, 1, columnCell.h + 1, fCalcDocument.fCellsView.fNumOfRows + 1);
  2645.         RectRgn(cellsInColumn, aRect);
  2646.         UnionRgn(cellsInColumn, cellsToSelect, cellsToSelect);
  2647.         END;
  2648.  
  2649.     BEGIN
  2650.     aCell := cellRegion^^.rgnBBox.topLeft;
  2651.     IF NOT EqualRect(cellRegion^^.rgnBBox, fSelections^^.rgnBBox) THEN
  2652.         BEGIN                                            { selection has changed }
  2653.         WITH fCalcDocument DO
  2654.             BEGIN
  2655.             fCellsView.SetEmptySelection(kHighlight);
  2656.             fRowsView.SetEmptySelection(kHighlight);
  2657.             fColumnIsSelected := TRUE;
  2658.             END;
  2659.         SetSelection(cellRegion, kDontExtend, kHighlight, kSelect);
  2660.         cellsToSelect := MakeNewRgn;
  2661.         cellsInColumn := MakeNewRgn;
  2662.         EachSelectedCellDo(GetColumnCells);             { add cells in the column to cellsToSelect }
  2663.         fCalcDocument.fCellsView.SetSelection(cellsToSelect, kDontExtend, kHighlight, kSelect);
  2664.         DisposeRgn(cellsToSelect);
  2665.         DisposeRgn(cellsInColumn);
  2666.         END;
  2667.     END;
  2668.  
  2669. {--------------------------------------------------------------------------------------------------}
  2670. {$S AFields}
  2671.  
  2672. PROCEDURE TColumnsView.Fields(PROCEDURE DoToField(fieldName: Str255;
  2673.                                                   fieldAddr: Ptr;
  2674.                                                   fieldType: INTEGER)); OVERRIDE;
  2675.  
  2676.     BEGIN
  2677.     DoToField('TColumnsView', NIL, bClass);
  2678.     DoToField('fCalcDocument', @fCalcDocument, bObject);
  2679.     INHERITED Fields(DoToField);
  2680.     END;
  2681.  
  2682. {***************************************************************************************************
  2683.     T C a l c P r i n t H a n d l e r
  2684. ***************************************************************************************************}
  2685. {$S ANonRes}
  2686.  
  2687. PROCEDURE TCalcPrintHandler.CalcViewPerPage(VAR amtPerPage: VPoint); OVERRIDE;
  2688.  
  2689.     VAR
  2690.         noOfRows:            INTEGER;
  2691.  
  2692.     BEGIN
  2693.     INHERITED CalcViewPerPage(amtPerPage);
  2694.     noOfRows := amtPerPage.v DIV kCellHeight;
  2695.     amtPerPage.v := noOfRows * kCellHeight;
  2696.     END;
  2697.  
  2698. {--------------------------------------------------------------------------------------------------}
  2699. {$S ANonRes}
  2700.  
  2701. FUNCTION TCalcPrintHandler.DoMenuCommand(aCmdNumber: cmdNumber): TCommand; OVERRIDE;
  2702. { Overridden to handle Print Selection. }
  2703.  
  2704.     BEGIN
  2705.     DoMenuCommand := NIL;
  2706.     fCmdNumber := aCmdNumber;                            { Save cmd number for GetPrintExtent }
  2707.     IF aCmdNumber = cPrintSelection THEN
  2708.         aCmdNumber := cPrint;                            { proceed like regular Print }
  2709.     DoMenuCommand := INHERITED DoMenuCommand(aCmdNumber);
  2710.     END;
  2711.  
  2712. {--------------------------------------------------------------------------------------------------}
  2713. {$S ANonRes}
  2714.  
  2715. PROCEDURE TCalcPrintHandler.DoSetupMenus; OVERRIDE;
  2716. { Overridden to handle Print Selection. }
  2717.  
  2718.     BEGIN
  2719.     INHERITED DoSetupMenus;
  2720.     Enable(cPrintSelection, gCouldPrint & (fView <> NIL));
  2721.     END;
  2722.  
  2723. {***************************************************************************************************
  2724.     T E n t r y V i e w
  2725. ***************************************************************************************************}
  2726. {$S AOpen}
  2727.  
  2728. PROCEDURE TEntryView.IRes(itsDocument: TDocument;
  2729.                           itsSuperView: TView;
  2730.                           VAR itsParams: Ptr); OVERRIDE;
  2731.  
  2732.     VAR
  2733.         minSize:            Point;
  2734.  
  2735.     BEGIN
  2736.     INHERITED IRes(NIL, itsSuperView, itsParams);        { set itsDocument to NIL since this guy
  2737.                                                          doesn't affect the document }
  2738.     fCalcDocument := TCalcDocument(itsDocument);
  2739.     fTouched := FALSE;
  2740.     fTEditing := FALSE;
  2741.     fFirstEdit := FALSE;
  2742.     fOldString := '';
  2743.     END;
  2744.  
  2745. {--------------------------------------------------------------------------------------------------}
  2746. {$S ARes}
  2747.  
  2748. FUNCTION TEntryView.DoKeyCommand(Ch: CHAR;
  2749.                                  aKeyCode: INTEGER;
  2750.                                  VAR info: EventInfo): TCommand; OVERRIDE;
  2751.  
  2752.     BEGIN
  2753.     { If this is the first character, wipe out old value and activate caret. }
  2754.     IF (NOT fTEditing) & ((Ch >= ' ') | (Ch = chBackspace)) THEN
  2755.         SetEditMode;
  2756.     DoKeyCommand := INHERITED DoKeyCommand(Ch, aKeyCode, info);
  2757.     END;
  2758.  
  2759. {--------------------------------------------------------------------------------------------------}
  2760. {$S ASelCommand}
  2761.  
  2762. FUNCTION TEntryView.DoMakeTypingCommand(Ch: CHAR): TTETypingCommand; OVERRIDE;
  2763.  
  2764.     VAR
  2765.         aTypingCommand:     TCalcTypingCommand;
  2766.  
  2767.     BEGIN
  2768.     NEW(aTypingCommand);
  2769.     FailNIL(aTypingCommand);
  2770.     aTypingCommand.ITETypingCommand(SELF, Ch);
  2771.     DoMakeTypingCommand := aTypingCommand;
  2772.     END;
  2773.  
  2774. {--------------------------------------------------------------------------------------------------}
  2775. {$S ASelCommand}
  2776.  
  2777. FUNCTION TEntryView.DoMouseCommand(VAR theMouse: Point;
  2778.                                    VAR info: EventInfo;
  2779.                                    VAR hysteresis: Point): TCommand; OVERRIDE;
  2780.  
  2781.     BEGIN
  2782.     { If no characters typed, active caret, then handle mouse down. }
  2783.     IF NOT fTouched THEN
  2784.         InstallSelection(FALSE, TRUE);
  2785.     EditMode(TRUE);
  2786.     DoMouseCommand := INHERITED DoMouseCommand(theMouse, info, hysteresis);
  2787.     END;
  2788.  
  2789. {--------------------------------------------------------------------------------------------------}
  2790. {$S ARes}
  2791.  
  2792. PROCEDURE TEntryView.DoSetupMenus; OVERRIDE;
  2793.  
  2794.     BEGIN
  2795.     { TTEView.DoSetupMenus will setup the Edit menu commands for us. }
  2796.     INHERITED DoSetupMenus;
  2797.  
  2798.     IF fTEditing THEN
  2799.         BEGIN
  2800.         SetEditCmdName(cCut, cCutText);
  2801.         SetEditCmdName(cCopy, cCopyText);
  2802.         SetEditCmdName(cClear, cClearText);
  2803.         END;
  2804.     END;
  2805.  
  2806. {--------------------------------------------------------------------------------------------------}
  2807. {$S ARes}
  2808.  
  2809. PROCEDURE TEntryView.Draw(area: Rect); OVERRIDE;
  2810.  
  2811.     VAR
  2812.         r:                    Rect;
  2813.  
  2814.     BEGIN
  2815.     INHERITED Draw(area);
  2816.  
  2817.     { We want a rectangle around the whole view }
  2818.     PenSize(1, 1);
  2819.     PenPat(black);
  2820.     GetQDExtent(r);
  2821.     FrameRect(r);
  2822.  
  2823.     INHERITED Draw(area);
  2824.     END;
  2825.  
  2826. {--------------------------------------------------------------------------------------------------}
  2827. {$S ASelCommand}
  2828.  
  2829. PROCEDURE TEntryView.EditMode(editing: BOOLEAN);
  2830.  
  2831.     VAR
  2832.         lastCommand:        TCommand;
  2833.  
  2834.     BEGIN
  2835.     fTEditing := editing;
  2836.     fFirstEdit := FALSE;                                { set to TRUE only by DoKeyCommand }
  2837.  
  2838.     IF editing THEN
  2839.         BEGIN
  2840.         {$Push} {$H-}
  2841.         GetAsString(fOldString);                        { save previous string for Undo/Redo }
  2842.         {$Pop}
  2843.         END
  2844.     ELSE
  2845.         BEGIN                                            { disable undo/redo for TTECommands. ???
  2846.                                                          There must be a better way! this is
  2847.                                                          disgusting! }
  2848.         lastCommand := GetLastCommand;
  2849.         IF lastCommand <> NIL THEN
  2850.             IF GetSuperClassID(GetClassID(lastCommand)) = GetClassIDFromName('TTECommand') THEN
  2851.                 lastCommand.fCanUndo := FALSE;
  2852.         END;
  2853.     END;
  2854.  
  2855. {--------------------------------------------------------------------------------------------------}
  2856. {$S ARes}
  2857.  
  2858. PROCEDURE TEntryView.GetAsString(VAR theString: Str255);
  2859.  
  2860.     VAR
  2861.         theText:            CharsHandle;
  2862.         numberOfChars:        INTEGER;
  2863.         i:                    INTEGER;
  2864.  
  2865.     BEGIN
  2866.     theText := TEGetText(fHTE);
  2867.     numberOfChars := Min(255, GetHandleSize(Handle(theText)));
  2868.     theString[0] := CHR(numberOfChars);
  2869.     FOR i := 1 TO numberOfChars DO
  2870.         theString[i] := theText^^[i - 1];
  2871.     END;
  2872.  
  2873. {--------------------------------------------------------------------------------------------------}
  2874. {$S ARes}
  2875.  
  2876. PROCEDURE TEntryView.InstallSelection(wasActive, beActive: BOOLEAN); OVERRIDE;
  2877.  
  2878.     VAR
  2879.         r:                    Rect;
  2880.  
  2881.     BEGIN
  2882.     INHERITED InstallSelection(wasActive, beActive);
  2883.  
  2884.     TESetSelect(0, 0, fHTE);
  2885.     fTouched := beActive;
  2886.     IF Focus THEN
  2887.         BEGIN
  2888.         GetQDExtent(r);
  2889.         InsetRect(r, 2, 2);
  2890.         InvalidRect(r);
  2891.         END;
  2892.     END;
  2893.  
  2894. {--------------------------------------------------------------------------------------------------}
  2895. {$S ASelCommand}
  2896.  
  2897. PROCEDURE TEntryView.SetEditMode;
  2898.  
  2899.     BEGIN
  2900.     EditMode(TRUE);                                     { sets fFirstEdit to FALSE }
  2901.     fFirstEdit := TRUE;                                 { the only place it is set to TRUE }
  2902.     SetToString('');
  2903.     InstallSelection(FALSE, TRUE);
  2904.     END;
  2905.  
  2906. {--------------------------------------------------------------------------------------------------}
  2907. {$S ARes}
  2908.  
  2909. PROCEDURE TEntryView.SetToString(theString: Str255);
  2910.  
  2911.     BEGIN
  2912.     IF Focus THEN;
  2913.     SetJustification(teJustSystem, kDontRedraw);        { initialize text to system-justified }
  2914.     InstallSelection(TRUE, FALSE);
  2915.     TESetText(Ptr(ORD4(@theString) + 1), LENGTH(theString), fHTE);
  2916.     END;
  2917.  
  2918. {--------------------------------------------------------------------------------------------------}
  2919. {$S ADoCommand}
  2920.  
  2921. PROCEDURE TEntryView.SwapStrings;
  2922.  
  2923.     VAR
  2924.         newString:            Str255;
  2925.  
  2926.     BEGIN
  2927.     newString := fOldString;
  2928.     {$Push} {$H-}
  2929.     GetAsString(fOldString);
  2930.     {$Pop}
  2931.     SetToString(newString);
  2932.     fTouched := TRUE;
  2933.     END;
  2934.  
  2935. {--------------------------------------------------------------------------------------------------}
  2936. {$S AFields}
  2937.  
  2938. PROCEDURE TEntryView.Fields(PROCEDURE DoToField(fieldName: Str255;
  2939.                                                 fieldAddr: Ptr;
  2940.                                                 fieldType: INTEGER)); OVERRIDE;
  2941.  
  2942.     BEGIN
  2943.     DoToField('TEntryView', NIL, bClass);
  2944.     DoToField('fCalcDocument', @fCalcDocument, bObject);
  2945.     DoToField('fTouched', @fTouched, bBoolean);
  2946.     DoToField('fTEditing', @fTEditing, bBoolean);
  2947.     DoToField('fFirstEdit', @fFirstEdit, bBoolean);
  2948.     DoToField('fOldString', @fOldString, bString);
  2949.     INHERITED Fields(DoToField);
  2950.     END;
  2951.  
  2952. {***************************************************************************************************
  2953.     T C o o r d V i e w
  2954. ***************************************************************************************************}
  2955. {$S AOpen}
  2956.  
  2957. PROCEDURE TCoordView.IRes(itsDocument: TDocument;
  2958.                           itsSuperView: TView;
  2959.                           VAR itsParams: Ptr); OVERRIDE;
  2960.  
  2961.     VAR
  2962.         minSize:            Point;
  2963.  
  2964.     BEGIN
  2965.     fCalcDocument := TCalcDocument(itsDocument);
  2966.     INHERITED IRes(itsDocument, itsSuperView, itsParams);
  2967.     END;
  2968.  
  2969. {--------------------------------------------------------------------------------------------------}
  2970. {$S ARes}
  2971.  
  2972. PROCEDURE TCoordView.Draw(area: Rect);
  2973.  
  2974.     VAR
  2975.         aString, anotherString: Str255;
  2976.         aRect:Rect;
  2977.  
  2978.     BEGIN
  2979.     WITH fCalcDocument DO
  2980.         BEGIN
  2981.         IF fEditColumn > 0 THEN
  2982.             fColumnsView.CoordToString(fEditColumn, aString)
  2983.         ELSE
  2984.             aString := ' ';
  2985.  
  2986.         IF fEditRow > 0 THEN
  2987.             NumToString(fEditRow, anotherString)
  2988.         ELSE
  2989.             anotherString := ' ';
  2990.         END;
  2991.     aString := CONCAT(aString, anotherString);
  2992.     SetTheFont(kEntryFont, kEntryFontSize, [bold]);
  2993.     SetRect(aRect, 2, 0, 46, kEntryHeight);
  2994.     SmartDrawString(aString, aRect, teJustSystem);
  2995.  
  2996.     INHERITED Draw(area);
  2997.     END;
  2998.  
  2999. {--------------------------------------------------------------------------------------------------}
  3000. {$S AFields}
  3001.  
  3002. PROCEDURE TCoordView.Fields(PROCEDURE DoToField(fieldName: Str255;
  3003.                                                 fieldAddr: Ptr;
  3004.                                                 fieldType: INTEGER)); OVERRIDE;
  3005.  
  3006.     BEGIN
  3007.     DoToField('TCoordView', NIL, bClass);
  3008.     DoToField('fCalcDocument', @fCalcDocument, bObject);
  3009.     INHERITED Fields(DoToField);
  3010.     END;
  3011.  
  3012. {***************************************************************************************************
  3013.     T C o l u m n
  3014. ***************************************************************************************************}
  3015. {$S ARes}
  3016.  
  3017. PROCEDURE TColumn.Initialize; OVERRIDE;
  3018. { Put the object into a known state from which it may be safely FREEd.
  3019.  (and hopefully a usable state) }
  3020.  
  3021.     BEGIN
  3022.     INHERITED Initialize;
  3023.  
  3024.     fNumber := 0;
  3025.     fFormat := gDefaultFormat;
  3026.     fWidth := kCellWidth;
  3027.     END;
  3028.  
  3029. {--------------------------------------------------------------------------------------------------}
  3030. {$S ARes}
  3031.  
  3032. PROCEDURE TColumn.IColumn(number: INTEGER);
  3033.  
  3034.     BEGIN
  3035.     IObject;
  3036.  
  3037.     fNumber := number;
  3038.     END;
  3039.  
  3040. {--------------------------------------------------------------------------------------------------}
  3041. {$S AFields}
  3042.  
  3043. PROCEDURE TColumn.Fields(PROCEDURE DoToField(fieldName: Str255;
  3044.                                              fieldAddr: Ptr;
  3045.                                              fieldType: INTEGER)); OVERRIDE;
  3046.  
  3047.     BEGIN
  3048.     DoToField('TColumn', NIL, bClass);
  3049.     DoToField('fNumber', @fNumber, bInteger);
  3050.     {$Push} {$H-}                                        { Because FormatFields is in a debugging
  3051.                                                          (i.e. resident) segment) }
  3052.     FormatFields('fFormat', fFormat, DoToField);
  3053.     {$Pop}
  3054.     DoToField('fWidth', @fWidth, bInteger);
  3055.  
  3056.     INHERITED Fields(DoToField);
  3057.     END;
  3058.  
  3059. {--------------------------------------------------------------------------------------------------}
  3060. {$S AReadFile}
  3061.  
  3062. PROCEDURE TColumn.ReadFromDisk(theRefNum: INTEGER);
  3063.  
  3064.     VAR
  3065.         columnInfo:         ColumnDiskInfo;
  3066.  
  3067.     BEGIN
  3068.     ReadBytes(theRefNum, SIZEOF(columnInfo), @columnInfo);
  3069.     WITH columnInfo DO
  3070.         BEGIN
  3071.         fNumber := number;
  3072.         fFormat := format;
  3073.         fWidth := width;
  3074.         END;
  3075.     END;
  3076.  
  3077. {--------------------------------------------------------------------------------------------------}
  3078. {$S AClipBoard}
  3079.  
  3080. PROCEDURE TColumn.ReadFromScrap(theScrap: Handle;
  3081.                                 VAR scrapOffset: LONGINT);
  3082.  
  3083.     VAR
  3084.         columnInfo:         ColumnDiskInfo;
  3085.  
  3086.     BEGIN
  3087.     ReadScrap(theScrap, scrapOffset, @columnInfo, SIZEOF(columnInfo));
  3088.     WITH columnInfo DO
  3089.         BEGIN
  3090.         fNumber := number;
  3091.         fFormat := format;
  3092.         fWidth := width;
  3093.         END;
  3094.     END;
  3095.  
  3096. {--------------------------------------------------------------------------------------------------}
  3097. {$S AWriteFile}
  3098.  
  3099. PROCEDURE TColumn.WriteToDisk(theRefNum: INTEGER);
  3100.  
  3101.     VAR
  3102.         columnInfo:         ColumnDiskInfo;
  3103.         theColumn:            ColumnNumber;
  3104.  
  3105.     BEGIN
  3106.     theColumn := fNumber;
  3107.     WriteBytes(theRefNum, SIZEOF(ColumnNumber), @theColumn);
  3108.  
  3109.     WITH columnInfo DO
  3110.         BEGIN
  3111.         number := fNumber;
  3112.         format := fFormat;
  3113.         width := fWidth;
  3114.         END;
  3115.     WriteBytes(theRefNum, SIZEOF(columnInfo), @columnInfo);
  3116.     END;
  3117.  
  3118. {--------------------------------------------------------------------------------------------------}
  3119. {$S AClipBoard}
  3120.  
  3121. PROCEDURE TColumn.WriteToScrap(theScrap: Handle;
  3122.                                VAR scrapOffset: LONGINT);
  3123.  
  3124.     VAR
  3125.         columnInfo:         ColumnDiskInfo;
  3126.  
  3127.     BEGIN
  3128.     WITH columnInfo DO
  3129.         BEGIN
  3130.         number := fNumber;
  3131.         format := fFormat;
  3132.         width := fWidth;
  3133.         END;
  3134.     WriteScrap(theScrap, scrapOffset, @columnInfo, SIZEOF(columnInfo));
  3135.     END;
  3136.  
  3137. {***************************************************************************************************
  3138.     T R o w
  3139. ***************************************************************************************************}
  3140. {$S ARes}
  3141.  
  3142. PROCEDURE TRow.Initialize; OVERRIDE;
  3143. { Put the object into a known state from which it may be safely FREEd.
  3144.  (and hopefully a usable state) }
  3145.  
  3146.     BEGIN
  3147.     INHERITED Initialize;
  3148.  
  3149.     fNumber := 0;
  3150.     END;
  3151.  
  3152. {--------------------------------------------------------------------------------------------------}
  3153. {$S ARes}
  3154.  
  3155. PROCEDURE TRow.IRow(number: INTEGER);
  3156.  
  3157.     BEGIN
  3158.     IObject;
  3159.  
  3160.     fNumber := number;
  3161.     END;
  3162.  
  3163. {--------------------------------------------------------------------------------------------------}
  3164. {$S AFields}
  3165.  
  3166. PROCEDURE TRow.Fields(PROCEDURE DoToField(fieldName: Str255;
  3167.                                           fieldAddr: Ptr;
  3168.                                           fieldType: INTEGER)); OVERRIDE;
  3169.  
  3170.     BEGIN
  3171.     DoToField('TRow', NIL, bClass);
  3172.     DoToField('fNumber', @fNumber, bInteger);
  3173.     INHERITED Fields(DoToField)
  3174.     END;
  3175.  
  3176. {--------------------------------------------------------------------------------------------------}
  3177. {$S AReadFile}
  3178.  
  3179. PROCEDURE TRow.ReadFromDisk(theRefNum: INTEGER);
  3180.  
  3181.     VAR
  3182.         RowInfo:            RowDiskInfo;
  3183.  
  3184.     BEGIN
  3185.     ReadBytes(theRefNum, SIZEOF(RowInfo), @RowInfo);
  3186.     WITH RowInfo DO
  3187.         fNumber := number;
  3188.     END;
  3189.  
  3190. {--------------------------------------------------------------------------------------------------}
  3191. {$S AClipBoard}
  3192.  
  3193. PROCEDURE TRow.ReadFromScrap(theScrap: Handle;
  3194.                              VAR scrapOffset: LONGINT);
  3195.  
  3196.     VAR
  3197.         RowInfo:            RowDiskInfo;
  3198.  
  3199.     BEGIN
  3200.     ReadScrap(theScrap, scrapOffset, @RowInfo, SIZEOF(RowInfo));
  3201.     WITH RowInfo DO
  3202.         fNumber := number;
  3203.     END;
  3204.  
  3205. {--------------------------------------------------------------------------------------------------}
  3206. {$S AWriteFile}
  3207.  
  3208. PROCEDURE TRow.WriteToDisk(theRefNum: INTEGER);
  3209.  
  3210.     VAR
  3211.         RowInfo:            RowDiskInfo;
  3212.         theRow:             RowNumber;
  3213.  
  3214.     BEGIN
  3215.     theRow := fNumber;
  3216.     WriteBytes(theRefNum, SIZEOF(RowNumber), @theRow);
  3217.  
  3218.     WITH RowInfo DO
  3219.         number := fNumber;
  3220.     WriteBytes(theRefNum, SIZEOF(RowInfo), @RowInfo);
  3221.     END;
  3222.  
  3223. {--------------------------------------------------------------------------------------------------}
  3224. {$S AClipBoard}
  3225.  
  3226. PROCEDURE TRow.WriteToScrap(theScrap: Handle;
  3227.                             VAR scrapOffset: LONGINT);
  3228.  
  3229.     VAR
  3230.         RowInfo:            RowDiskInfo;
  3231.  
  3232.     BEGIN
  3233.     WITH RowInfo DO
  3234.         number := fNumber;
  3235.     WriteScrap(theScrap, scrapOffset, @RowInfo, SIZEOF(RowInfo));
  3236.     END;
  3237.  
  3238. {***************************************************************************************************
  3239.     T C e l l
  3240. ***************************************************************************************************}
  3241. {$S ARes}
  3242.  
  3243. PROCEDURE TCell.Initialize; OVERRIDE;
  3244.  
  3245.     BEGIN
  3246.     INHERITED Initialize;
  3247.  
  3248.     fCalcDocument := NIL;
  3249.     fDeleted := FALSE;
  3250.     fDependents := NIL;
  3251.     fReferences := NIL;
  3252.  
  3253.     fKind := EmptyCell;
  3254.     fError := NoError;
  3255.     fValue := 0.0;
  3256.     fValueString := '';
  3257.     fFormula := '';
  3258.     FailMemError;
  3259.  
  3260.     fRow := 0;
  3261.     fColumn := 0;
  3262.     fEvaluating := FALSE;
  3263.     fCalculating := FALSE;
  3264.     END;
  3265.  
  3266. {--------------------------------------------------------------------------------------------------}
  3267. {$S ARes}
  3268.  
  3269. PROCEDURE TCell.ICell(owningDocument: TCalcDocument;
  3270.                       r: RowNumber;
  3271.                       c: ColumnNumber);
  3272.  
  3273.     BEGIN
  3274.     IObject;
  3275.  
  3276.     fCalcDocument := owningDocument;
  3277.  
  3278.     fDependents := NewList;
  3279.     FailNIL(fDependents);
  3280.  
  3281.     fReferences := NewList;
  3282.     FailNIL(fDependents);
  3283.  
  3284.     {$IFC qDebug}
  3285.     fDependents.SetEltType('TCell');
  3286.     fReferences.SetEltType('TCell');
  3287.     {$ENDC}
  3288.  
  3289.     fRow := r;
  3290.     fColumn := c;
  3291.     END;
  3292.  
  3293. {--------------------------------------------------------------------------------------------------}
  3294. {$S ARes}
  3295.  
  3296. PROCEDURE TCell.Free;
  3297.  
  3298.     BEGIN
  3299.     FreeIfObject(fDependents);
  3300.     fDependents := NIL;
  3301.  
  3302.     FreeIfObject(fReferences);
  3303.     fReferences := NIL;
  3304.  
  3305.     INHERITED Free;
  3306.     END;
  3307.  
  3308. {--------------------------------------------------------------------------------------------------}
  3309. {$S ARes}
  3310.  
  3311. FUNCTION TCell.Clone: TObject; OVERRIDE;
  3312.  
  3313.     VAR
  3314.         clonedCell:         TCell;
  3315.  
  3316.     BEGIN
  3317.     clonedCell := TCell(INHERITED Clone);
  3318.     FailNIL(clonedCell);
  3319.     clonedCell.fDependents := NIL;
  3320.     clonedCell.fReferences := NIL;
  3321.     Clone := TObject(clonedCell);
  3322.     END;
  3323.  
  3324. {--------------------------------------------------------------------------------------------------}
  3325. {$S ARes}
  3326.  
  3327. PROCEDURE TCell.CopyContents(sourceCell: TCell);
  3328.  
  3329.     BEGIN
  3330.     fKind := sourceCell.fKind;
  3331.     fFormula := sourceCell.fFormula;
  3332.     END;
  3333.  
  3334. {--------------------------------------------------------------------------------------------------}
  3335. {$S ARes}
  3336.  
  3337. PROCEDURE TCell.EvaluateFormula(DoReferences: BOOLEAN);
  3338.  
  3339.     VAR
  3340.         formulaLength:        INTEGER;
  3341.         formulaIndex:        INTEGER;
  3342.         theChar:            CHAR;
  3343.         theValue:            ValueType;
  3344.  
  3345. {--------------------------------------------------------------------------------------------------}
  3346.  
  3347.     FUNCTION Factor(VAR theValue: ValueType): EvalResult;
  3348.         FORWARD;
  3349.  
  3350. {--------------------------------------------------------------------------------------------------}
  3351.  
  3352.     FUNCTION Expression(VAR theValue: ValueType): EvalResult;
  3353.         FORWARD;
  3354.  
  3355. {--------------------------------------------------------------------------------------------------}
  3356.  
  3357.     PROCEDURE GetNextChar;
  3358.  
  3359.         BEGIN
  3360.         REPEAT
  3361.             IF formulaIndex < formulaLength THEN
  3362.                 BEGIN
  3363.                 formulaIndex := formulaIndex + 1;
  3364.                 theChar := fFormula[formulaIndex];
  3365.                 END
  3366.             ELSE
  3367.                 theChar := CHR(0);
  3368.         UNTIL theChar <> ' ';
  3369.         IF (theChar >= 'a') & (theChar <= 'z') THEN
  3370.             theChar := CHR(ORD(theChar) - 32);
  3371.         END;
  3372.  
  3373. {--------------------------------------------------------------------------------------------------}
  3374.  
  3375.     FUNCTION DoInteger(VAR theInteger: INTEGER): EvalResult;
  3376.  
  3377.         BEGIN
  3378.         theInteger := 0;
  3379.         WHILE IsDigit(theChar) DO
  3380.             BEGIN
  3381.             theInteger := theInteger * 10 + ORD(theChar) - ORD('0');
  3382.             GetNextChar;
  3383.             END;
  3384.         DoInteger := NoError;
  3385.         END;
  3386.  
  3387. {--------------------------------------------------------------------------------------------------}
  3388.  
  3389.     FUNCTION DoNumber(VAR theValue: ValueType): EvalResult;
  3390.     { DoNumber is called only when theChar is a numeric digit or a decimal point }
  3391.  
  3392.         VAR
  3393.             newIndex:            INTEGER;
  3394.             decimalNumber:        Decimal;
  3395.             IsValidNumber:        BOOLEAN;
  3396.             startsWithDecPt:    BOOLEAN;
  3397.             theFormula:         Str255;
  3398.  
  3399.         BEGIN
  3400.         startsWithDecPt := (theChar = '.');
  3401.         newIndex := formulaIndex;
  3402.         theFormula := fFormula;
  3403.         Str2Dec(theFormula, newIndex, decimalNumber, IsValidNumber);
  3404.         { Str2Dec returns IsValidNumber = FALSE if the digits are followed by non-numerics like * }
  3405.         IF startsWithDecPt & (NOT IsValidNumber) THEN
  3406.             BEGIN
  3407.             GetNextChar;
  3408.             IF NOT IsDigit(theChar) THEN
  3409.                 BEGIN
  3410.                 DoNumber := BadNumber;
  3411.                 EXIT(DoNumber);
  3412.                 END;
  3413.             END;
  3414.         formulaIndex := newIndex - 1;
  3415.         GetNextChar;
  3416.         theValue := Dec2Num(decimalNumber);
  3417.         DoNumber := NoError;
  3418.         END;
  3419.  
  3420. {--------------------------------------------------------------------------------------------------}
  3421.  
  3422.     FUNCTION DoCellReference(VAR theValue: ValueType): EvalResult;
  3423.  
  3424.         VAR
  3425.             theResult:            EvalResult;
  3426.             r:                    INTEGER;                { Can't use RowNumber because it may be }
  3427.             c:                    INTEGER;                { …out of range }
  3428.             referencedCell:     TCell;
  3429.             aRect:                Rect;
  3430.  
  3431.         BEGIN
  3432.         theResult := NoError;
  3433.         aRect := fCalcDocument.fDimensions;             { valid coordinates }
  3434.         c := 0;
  3435.         WHILE (theChar >= 'A') & (theChar <= 'Z') & (c <= aRect.right) DO
  3436.             BEGIN
  3437.             c := c * 26 + ORD(theChar) - ORD('A') + 1;
  3438.             GetNextChar;
  3439.             END;
  3440.         IF c > aRect.right THEN                         { column is out of range, so }
  3441.             r := 0                                        { …don't bother looking for row number }
  3442.         ELSE
  3443.             theResult := DoInteger(r);
  3444.         IF fCalcDocument.CellInRange(r, c, aRect) THEN
  3445.             BEGIN
  3446.             referencedCell := fCalcDocument.GetExistingCell(r - fCalcDocument.fRowOffset, c -
  3447.                                                             fCalcDocument.fColumnOffset);
  3448.             IF referencedCell = NIL THEN                { cell doesn't exist }
  3449.                 theValue := 0
  3450.             ELSE
  3451.                 BEGIN
  3452.                 IF referencedCell.fEvaluating THEN
  3453.                     theResult := SelfReference
  3454.                 ELSE IF (referencedCell.fKind = ErrorCell) THEN
  3455.                     theResult := ErrorCellReference
  3456.                 ELSE IF (referencedCell.fKind = TextCell) THEN
  3457.                     theValue := 0
  3458.                 ELSE
  3459.                     theValue := referencedCell.fValue;
  3460.  
  3461.                 IF DoReferences THEN
  3462.                     BEGIN
  3463.                     fReferences.InsertLast(referencedCell);
  3464.                     referencedCell.fDependents.InsertLast(SELF);
  3465.                     END;
  3466.                 END;
  3467.             END
  3468.         ELSE
  3469.             theResult := BadCellReference;
  3470.         DoCellReference := theResult;
  3471.         END;
  3472.  
  3473. {--------------------------------------------------------------------------------------------------}
  3474.  
  3475.     FUNCTION Term(VAR theValue: ValueType): EvalResult;
  3476.  
  3477.         BEGIN
  3478.         IF theChar = '(' THEN
  3479.             BEGIN
  3480.             GetNextChar;
  3481.             Term := Expression(theValue);
  3482.             IF theChar = ')' THEN
  3483.                 GetNextChar
  3484.             ELSE
  3485.                 Term := MissingRightParen;
  3486.             END
  3487.         ELSE IF IsDigit(theChar) | (theChar = '.') THEN
  3488.             Term := DoNumber(theValue)
  3489.         ELSE IF (theChar >= 'A') & (theChar <= 'Z') THEN
  3490.             Term := DoCellReference(theValue)
  3491.         ELSE IF theChar = '+' THEN
  3492.             BEGIN
  3493.             GetNextChar;
  3494.             Term := Term(theValue);
  3495.             END
  3496.         ELSE IF theChar = '-' THEN
  3497.             BEGIN
  3498.             GetNextChar;
  3499.             Term := Term(theValue);
  3500.             theValue := - theValue;
  3501.             END
  3502.         ELSE
  3503.             Term := IllegalCharacter;
  3504.         END;
  3505.  
  3506. {--------------------------------------------------------------------------------------------------}
  3507.  
  3508.     FUNCTION Factor(VAR theValue: ValueType): EvalResult;
  3509.  
  3510.         VAR
  3511.             theResult:            EvalResult;
  3512.             factorValue:        ValueType;
  3513.  
  3514.         BEGIN
  3515.         theResult := Term(theValue);
  3516.         IF theResult = NoError THEN
  3517.             IF theChar = '*' THEN
  3518.                 BEGIN
  3519.                 GetNextChar;
  3520.                 theResult := Factor(factorValue);
  3521.                 theValue := theValue * factorValue;
  3522.                 END
  3523.             ELSE IF theChar = '/' THEN
  3524.                 BEGIN
  3525.                 GetNextChar;
  3526.                 theResult := Factor(factorValue);
  3527.                 theValue := theValue / factorValue;
  3528.                 END;
  3529.         Factor := theResult;
  3530.         END;
  3531.  
  3532. {--------------------------------------------------------------------------------------------------}
  3533.  
  3534.     FUNCTION Expression(VAR theValue: ValueType): EvalResult;
  3535.  
  3536.         VAR
  3537.             factorResult:        EvalResult;
  3538.             factorValue:        ValueType;
  3539.  
  3540.         BEGIN
  3541.         factorResult := Factor(theValue);
  3542.         IF factorResult = NoError THEN
  3543.             REPEAT
  3544.                 IF theChar = '+' THEN
  3545.                     BEGIN
  3546.                     GetNextChar;
  3547.                     factorResult := Factor(factorValue);
  3548.                     theValue := theValue + factorValue;
  3549.                     END
  3550.                 ELSE IF theChar = '-' THEN
  3551.                     BEGIN
  3552.                     GetNextChar;
  3553.                     factorResult := Factor(factorValue);
  3554.                     theValue := theValue - factorValue;
  3555.                     END;
  3556.             UNTIL (theChar <> '+') & (theChar <> '-');
  3557.         Expression := factorResult;
  3558.         END;
  3559.  
  3560.     BEGIN                                                { EvaluateFormula }
  3561.     formulaLength := LENGTH(fFormula);
  3562.     formulaIndex := 0;
  3563.     GetNextChar;
  3564.     IF theChar IN ['=', '-', '+', '.', '0'..'9'] THEN
  3565.         BEGIN
  3566.         IF theChar = '=' THEN
  3567.             GetNextChar;
  3568.  
  3569.         fEvaluating := TRUE;                            { prevent self reference loop }
  3570.         fError := Expression(theValue);
  3571.         fEvaluating := FALSE;
  3572.  
  3573.         IF fError = NoError THEN
  3574.             BEGIN
  3575.             fValue := theValue;
  3576.             IF (formulaIndex <= formulaLength) & (theChar <> CHR(0)) THEN
  3577.                 fError := GarbageAtEnd;
  3578.             END;
  3579.         IF fError = NoError THEN
  3580.             fKind := ValueCell
  3581.         ELSE
  3582.             fKind := ErrorCell;
  3583.         END
  3584.     ELSE
  3585.         fKind := TextCell;
  3586.     END;
  3587.  
  3588. {--------------------------------------------------------------------------------------------------}
  3589. {$S ARes}
  3590.  
  3591. PROCEDURE TCell.GetAsString(VAR theString: Str255);
  3592.  
  3593.     BEGIN
  3594.     theString := fFormula;
  3595.     END;
  3596.  
  3597. {--------------------------------------------------------------------------------------------------}
  3598. {$S AWriteFile}
  3599.  
  3600. FUNCTION TCell.GetDiskSize(infoRecordOnly: BOOLEAN): INTEGER;
  3601.  
  3602.     VAR
  3603.         cellSize:            INTEGER;
  3604.  
  3605.     BEGIN
  3606.     cellSize := SIZEOF(CellDiskInfo) - SIZEOF(Str255) + LENGTH(fFormula) + 1;
  3607.     IF NOT infoRecordOnly THEN
  3608.         cellSize := cellSize + (fReferences.fSize + fDependents.fSize + 1) * SIZEOF(Point);
  3609.     GetDiskSize := cellSize;
  3610.     END;
  3611.  
  3612. {--------------------------------------------------------------------------------------------------}
  3613. {$S ARes}
  3614.  
  3615. PROCEDURE TCell.GetValueAsString(VAR theString: Str255);
  3616.  
  3617.     BEGIN
  3618.     CASE fKind OF
  3619.         TextCell:
  3620.             theString := fFormula;
  3621.         ValueCell:
  3622.             BEGIN
  3623.             IF fValueString = '' THEN
  3624.                 ValueToString;
  3625.             theString := fValueString;
  3626.             END;
  3627.         ErrorCell:
  3628.             BEGIN
  3629.             NumToString(ORD(fError), theString);
  3630.             theString := CONCAT('**ERROR ', theString);
  3631.             END;
  3632.         OTHERWISE
  3633.             theString := '';
  3634.     END;
  3635.     END;
  3636.  
  3637. {--------------------------------------------------------------------------------------------------}
  3638. {$S AFields}
  3639.  
  3640. PROCEDURE TCell.Fields(PROCEDURE DoToField(fieldName: Str255;
  3641.                                            fieldAddr: Ptr;
  3642.                                            fieldType: INTEGER)); OVERRIDE;
  3643.  
  3644.     VAR
  3645.         aString:            Str255;
  3646.  
  3647.     BEGIN
  3648.     DoToField('TCell', NIL, bClass);
  3649.     DoToField('fDeleted', @fDeleted, bBoolean);
  3650.     DoToField('fCalcDocument', @fCalcDocument, bObject);
  3651.     DoToField('fDependents', @fDependents, bObject);
  3652.     DoToField('fReferences', @fReferences, bObject);
  3653.     DoToField('fRow', @fRow, bByte);
  3654.     DoToField('fColumn', @fColumn, bByte);
  3655.     CASE fKind OF
  3656.         EmptyCell:
  3657.             aString := 'Empty';
  3658.         ValueCell:
  3659.             aString := 'Value';
  3660.         TextCell:
  3661.             aString := 'Text';
  3662.         ErrorCell:
  3663.             aString := 'Error';
  3664.     END;
  3665.     DoToField('fKind', @aString, bString);
  3666.     CASE fError OF
  3667.         NoError:
  3668.             aString := 'None';
  3669.         MissingRightParen:
  3670.             aString := 'Missing right parenthesis';
  3671.         SelfReference:
  3672.             aString := 'Self reference';
  3673.         ErrorCellReference:
  3674.             aString := 'Reference to error cell';
  3675.         BadNumber:
  3676.             aString := 'Bad number';
  3677.         IllegalCharacter:
  3678.             aString := 'Illegal character';
  3679.         BadCellReference:
  3680.             aString := 'Bad cell reference';
  3681.         GarbageAtEnd:
  3682.             aString := 'Garbage at end';
  3683.     END;
  3684.     DoToField('fError', @aString, bString);
  3685.     DoToField('fValueString', @fValueString, bString);
  3686.     DoToField('fFormula', @fFormula, bString);
  3687.     DoToField('fEvaluating', @fEvaluating, bBoolean);
  3688.     DoToField('fCalculating', @fCalculating, bBoolean);
  3689.     INHERITED Fields(DoToField);
  3690.     END;
  3691.  
  3692. {--------------------------------------------------------------------------------------------------}
  3693. {$S AFields}
  3694.  
  3695. PROCEDURE TCell.GetInspectorName(VAR inspectorName: Str255); OVERRIDE;
  3696.  
  3697.     VAR
  3698.         aString, titleString: Str255;
  3699.  
  3700.     BEGIN
  3701.     IF IsObject(fCalcDocument.fColumnsView) THEN
  3702.         BEGIN
  3703.         fCalcDocument.fColumnsView.CoordToString(fColumn, aString);
  3704.         NumToString(fRow, inspectorName);
  3705.         fCalcDocument.GetInspectorName(titleString);
  3706.         inspectorName := CONCAT(titleString, ' ', aString, inspectorName);
  3707.         END;
  3708.     END;
  3709.  
  3710. {--------------------------------------------------------------------------------------------------}
  3711. {$S ARes}
  3712.  
  3713. PROCEDURE TCell.invalidate;
  3714.  
  3715.     VAR
  3716.         aCell:                GridCell;
  3717.  
  3718.     BEGIN
  3719.     aCell.h := fColumn;
  3720.     aCell.v := fRow;
  3721.     fCalcDocument.fCellsView.InvalidateCell(aCell);
  3722.     END;
  3723.  
  3724. {--------------------------------------------------------------------------------------------------}
  3725. {$S ARes}
  3726.  
  3727. FUNCTION TCell.IsEmpty: BOOLEAN;
  3728.  
  3729.     BEGIN
  3730.     IsEmpty := (fKind = EmptyCell) & (LENGTH(fFormula) = 0);
  3731.     END;
  3732.  
  3733. {--------------------------------------------------------------------------------------------------}
  3734. {$S AReadFile}
  3735.  
  3736. PROCEDURE TCell.ReadFromDisk(theRefNum: INTEGER);
  3737.  
  3738.     VAR
  3739.         cellLength:         INTEGER;
  3740.         cellInfo:            CellDiskInfo;
  3741.         referencedCell:     TCell;
  3742.         refRow:             RowNumber;
  3743.         refColumn:            ColumnNumber;
  3744.         refIndex:            INTEGER;
  3745.  
  3746.     BEGIN
  3747.     ReadBytes(theRefNum, SIZEOF(cellLength), @cellLength);
  3748.     ReadBytes(theRefNum, cellLength, @cellInfo);
  3749.  
  3750.     WITH cellInfo DO
  3751.         BEGIN
  3752.         fKind := kind;
  3753.         fError := error;
  3754.         fValue := value;
  3755.         fFormula := formula;
  3756.  
  3757.         FOR refIndex := 1 TO noOfReferences DO
  3758.             BEGIN
  3759.             ReadCellCoordinate(theRefNum, refRow, refColumn);
  3760.             referencedCell := fCalcDocument.GetCell(refRow, refColumn);
  3761.             fReferences.InsertLast(referencedCell);
  3762.             referencedCell.fDependents.InsertLast(SELF);
  3763.             END;
  3764.         END;
  3765.     END;
  3766.  
  3767. {--------------------------------------------------------------------------------------------------}
  3768. {$S AClipBoard}
  3769.  
  3770. PROCEDURE TCell.ReadFromScrap(theScrap: Handle;
  3771.                               VAR scrapOffset: LONGINT);
  3772.  
  3773.     VAR
  3774.         cellLength:         INTEGER;
  3775.         cellInfo:            CellDiskInfo;
  3776.         referencedCell:     TCell;
  3777.         cellCoord:            Point;
  3778.         refIndex:            INTEGER;
  3779.  
  3780.     BEGIN
  3781.     ReadScrap(theScrap, scrapOffset, @cellLength, SIZEOF(cellLength));
  3782.     ReadScrap(theScrap, scrapOffset, @cellInfo, cellLength);
  3783.  
  3784.     WITH cellInfo DO
  3785.         BEGIN
  3786.         fKind := kind;
  3787.         fError := error;
  3788.         fValue := value;
  3789.         fFormula := formula;
  3790.  
  3791.         FOR refIndex := 1 TO noOfReferences DO
  3792.             BEGIN
  3793.             ReadScrap(theScrap, scrapOffset, @cellCoord, SIZEOF(cellCoord));
  3794.             referencedCell := fCalcDocument.GetCell(cellCoord.v, cellCoord.h);
  3795.             fReferences.InsertLast(referencedCell);
  3796.             referencedCell.fDependents.InsertLast(SELF);
  3797.             END;
  3798.         END;
  3799.     END;
  3800.  
  3801. {--------------------------------------------------------------------------------------------------}
  3802. {$S ARes}
  3803.  
  3804. PROCEDURE TCell.Recalculate(forceAutomatic: BOOLEAN;
  3805.                             setDependents: BOOLEAN);
  3806.  
  3807. {--------------------------------------------------------------------------------------------------}
  3808.  
  3809.     PROCEDURE RemoveDependent(theObject: TObject);
  3810.  
  3811.         BEGIN
  3812.         TCell(theObject).fDependents.Delete(TObject(SELF));
  3813.         END;
  3814.  
  3815. {--------------------------------------------------------------------------------------------------}
  3816.  
  3817.     PROCEDURE CalculateCell(theObject: TObject);
  3818.  
  3819.         VAR
  3820.             theCell:            TCell;
  3821.             oldValue:            ValueType;
  3822.             oldKind:            KindOfCell;
  3823.             shouldInvalidate:    BOOLEAN;
  3824.  
  3825.         BEGIN
  3826.         theCell := TCell(theObject);
  3827.         WITH theCell DO
  3828.             BEGIN
  3829.             IF NOT fCalculating THEN
  3830.                 BEGIN
  3831.                 fCalculating := TRUE;                    { prevent circular reference loop }
  3832.                 fValueString := '';
  3833.                 oldValue := fValue;
  3834.                 oldKind := fKind;
  3835.                 EvaluateFormula(setDependents);
  3836.                 shouldInvalidate := (oldValue <> fValue) | (oldKind <> fKind);
  3837.                 IF shouldInvalidate | setDependents THEN
  3838.                     BEGIN
  3839.                     setDependents := FALSE;
  3840.                     IF shouldInvalidate THEN
  3841.                         theCell.invalidate;
  3842.                     IF forceAutomatic | fCalcDocument.IsAutoCalc THEN
  3843.                         fDependents.Each(CalculateCell);
  3844.                     END;
  3845.                 fCalculating := FALSE;
  3846.                 END;
  3847.             END;
  3848.         END;
  3849.  
  3850.     BEGIN
  3851.     IF setDependents THEN
  3852.         BEGIN
  3853.         fReferences.Each(RemoveDependent);
  3854.         fReferences.DeleteAll;
  3855.         END;
  3856.     CalculateCell(TObject(SELF));
  3857.     END;
  3858.  
  3859. {--------------------------------------------------------------------------------------------------}
  3860. {$S ARes}
  3861.  
  3862. PROCEDURE TCell.SetDeleteState(deleted: BOOLEAN);
  3863.  
  3864.     BEGIN
  3865.     fDeleted := deleted;
  3866.     END;
  3867.  
  3868. {--------------------------------------------------------------------------------------------------}
  3869. {$S ARes}
  3870.  
  3871. PROCEDURE TCell.SetToString(theString: Str255);
  3872.  
  3873.     VAR
  3874.         theOldString:        Str255;
  3875.  
  3876.     BEGIN
  3877.     GetAsString(theOldString);
  3878.     IF theString <> theOldString THEN
  3879.         BEGIN
  3880.         fFormula := theString;
  3881.         fKind := EmptyCell;                             { Force Recalculate to invalidate the cell }
  3882.         Recalculate(NOT kForceAutomatic, kSetDependents); { we want to set new dependents }
  3883.         END;
  3884.     END;
  3885.  
  3886. {--------------------------------------------------------------------------------------------------}
  3887. {$S ARes}
  3888.  
  3889. PROCEDURE TCell.ValueToString;
  3890.  { Fills fValueString with the string representation of the cell's value.
  3891.    The "general" format is complicated because we try to ensure that
  3892.    the string will fit within the cell's column width.  Thus we have
  3893.    to figure out the appropriate representation for the value. }
  3894.  
  3895.     VAR
  3896.         aString:            Str255;
  3897.         theFormat:            DecForm;
  3898.         d:                    Decimal;
  3899.         i:                    INTEGER;
  3900.         len:                INTEGER;
  3901.         sigDigits:            INTEGER;
  3902.         leftDigits:         INTEGER;
  3903.         rightDigits:        INTEGER;
  3904.         width:                INTEGER;
  3905.         digitWidth:         INTEGER;
  3906.         dotWidth:            INTEGER;
  3907.         eWidth:             INTEGER;
  3908.         minusWidth:         INTEGER;
  3909.         plusWidth:            INTEGER;
  3910.         aColumn:            TColumn;
  3911.         aValueType:         ValueType;
  3912.  
  3913.     BEGIN
  3914.     aColumn := fCalcDocument.GetColumn(fColumn);
  3915.     WITH aColumn DO
  3916.         CASE fFormat.fStyle OF
  3917.             General:
  3918.                 BEGIN
  3919.                 SetTheFont(fFormat.fFontNumber, fFormat.fFontSize, fFormat.fFontStyle);
  3920.                 digitWidth := CharWidth('0');
  3921.                 dotWidth := CharWidth('.');
  3922.                 eWidth := CharWidth('e');
  3923.                 minusWidth := CharWidth('-');
  3924.                 plusWidth := CharWidth('+');
  3925.                 width := fCalcDocument.fCellsView.GetColWidth(fColumn) - (kCellHBorder * 2);
  3926.  
  3927.                 theFormat := gGeneralFormat;
  3928.                 aValueType := fValue;
  3929.                 Num2Dec(theFormat, aValueType, d);
  3930.                 aString := d.sig;
  3931.                 len := LENGTH(aString);
  3932.  
  3933.                 IF d.sgn = 1 THEN
  3934.                     width := width - minusWidth;
  3935.  
  3936.                 IF d.exp > 0 THEN
  3937.                 { We've exceeded the precision of our value representation }
  3938.                     BEGIN
  3939.                     theFormat.Style := FloatDecimal;
  3940.                     { account for '.' and '+e99' }
  3941.                     width := width - dotWidth - CharWidth('+') - eWidth - digitWidth - digitWidth;
  3942.                     theFormat.digits := Min(kValuePrecision, width DIV digitWidth);
  3943.                     END
  3944.                 ELSE
  3945.                     BEGIN
  3946.  
  3947.                     { determine number of significant digits }
  3948.                     sigDigits := 1;                     { in case all digits are zero }
  3949.                     FOR i := len DOWNTO 2 DO
  3950.                         IF aString[i] <> '0' THEN
  3951.                             BEGIN
  3952.                             sigDigits := i;
  3953.                             LEAVE;
  3954.                             END;
  3955.  
  3956.                     leftDigits := kValuePrecision + d.exp;
  3957.                     rightDigits := sigDigits - leftDigits;
  3958.  
  3959.                     IF leftDigits < sigDigits THEN
  3960.                         width := width - dotWidth;        { account for decimal point }
  3961.  
  3962.                     IF leftDigits * digitWidth > width THEN
  3963.                         BEGIN
  3964.                         { We must convert to scientific notation }
  3965.  
  3966.                         { account for decimal point and 'e9' }
  3967.                         width := width - dotWidth - eWidth - digitWidth;
  3968.  
  3969.      { For positive numbers, SANE puts a space (' ') before
  3970.       the first significant digit. }
  3971.                         IF d.sgn <> 1 THEN
  3972.                             width := width - CharWidth(' ');
  3973.                         IF d.exp < - kValuePrecision THEN
  3974.                             width := width - minusWidth
  3975.                         ELSE
  3976.                             width := width - plusWidth;
  3977.                         IF leftDigits > 10 THEN
  3978.                             width := width - digitWidth; { account for double-digit exponents }
  3979.  
  3980.                         theFormat.Style := FloatDecimal;
  3981.                         theFormat.digits := Min(sigDigits, width DIV digitWidth);
  3982.                         END
  3983.                     ELSE
  3984.                         BEGIN
  3985.                         theFormat.Style := FixedDecimal;
  3986.                         theFormat.digits := Min((width - (leftDigits * digitWidth) - dotWidth) DIV
  3987.                                                 digitWidth, rightDigits);
  3988.                         IF theFormat.digits < 0 THEN
  3989.                             theFormat.digits := 0;
  3990.                         END;
  3991.                     END;
  3992.                 END;
  3993.             DecimalStyle:
  3994.                 theFormat := gDecimalFormat;
  3995.             NoDecimal:
  3996.                 theFormat := gNoDecimalFormat;
  3997.             Scientific:
  3998.                 theFormat := gScientificFormat;
  3999.         END;
  4000.  
  4001.     aValueType := fValue;
  4002.     Num2Str(theFormat, aValueType, DecStr(aString));
  4003.     IF aString[1] = ' ' THEN
  4004.         Delete(aString, 1, 1);                            { Remove leading space }
  4005.     fValueString := Copy(aString, 1, Min(kMaxValueLength, LENGTH(aString)));
  4006.     END;
  4007.  
  4008. {--------------------------------------------------------------------------------------------------}
  4009. {$S AWriteFile}
  4010.  
  4011. PROCEDURE TCell.WriteToDisk(theRefNum: INTEGER);
  4012.  
  4013.     VAR
  4014.         cellInfo:            CellDiskInfo;
  4015.         cellLength:         INTEGER;
  4016.  
  4017. {--------------------------------------------------------------------------------------------------}
  4018.  
  4019.     PROCEDURE WriteCellCoordinate(theObject: TObject);
  4020.  
  4021.         VAR
  4022.             cellCoordinate:     Point;
  4023.  
  4024.         BEGIN
  4025.         cellCoordinate.v := TCell(theObject).fRow;
  4026.         cellCoordinate.h := TCell(theObject).fColumn;
  4027.         WriteBytes(theRefNum, SIZEOF(cellCoordinate), @cellCoordinate);
  4028.         END;
  4029.  
  4030.     BEGIN
  4031.     WriteCellCoordinate(TObject(SELF));
  4032.     cellLength := GetDiskSize(TRUE);                    { don't include ref's & dependents }
  4033.     WriteBytes(theRefNum, SIZEOF(cellLength), @cellLength);
  4034.     WITH cellInfo DO
  4035.         BEGIN
  4036.         kind := fKind;
  4037.         error := fError;
  4038.         value := fValue;
  4039.         noOfReferences := fReferences.fSize;
  4040.         formula := fFormula;
  4041.  
  4042.         WriteBytes(theRefNum, cellLength, @cellInfo);
  4043.  
  4044.         fReferences.Each(WriteCellCoordinate);
  4045.         END;
  4046.     END;
  4047.  
  4048. {--------------------------------------------------------------------------------------------------}
  4049. {$S AClipBoard}
  4050.  
  4051. PROCEDURE TCell.WriteToScrap(theScrap: Handle;
  4052.                              VAR scrapOffset: LONGINT);
  4053.  
  4054.     VAR
  4055.         cellInfo:            CellDiskInfo;
  4056.         cellLength:         INTEGER;
  4057.  
  4058. {--------------------------------------------------------------------------------------------------}
  4059.  
  4060.     PROCEDURE WriteCellCoordinate(theObject: TObject);
  4061.  
  4062.         VAR
  4063.             cellCoordinate:     Point;
  4064.  
  4065.         BEGIN
  4066.         cellCoordinate.v := TCell(theObject).fRow;
  4067.         cellCoordinate.h := TCell(theObject).fColumn;
  4068.         WriteScrap(theScrap, scrapOffset, @cellCoordinate, SIZEOF(cellCoordinate));
  4069.         END;
  4070.  
  4071.     BEGIN
  4072.     WriteCellCoordinate(TObject(SELF));
  4073.     cellLength := GetDiskSize(TRUE);                    { don't include ref's & dependents }
  4074.     WriteScrap(theScrap, scrapOffset, @cellLength, SIZEOF(cellLength));
  4075.     WITH cellInfo DO
  4076.         BEGIN
  4077.         kind := fKind;
  4078.         error := fError;
  4079.         value := fValue;
  4080.         noOfReferences := 0;                            { fReferences.fSize }
  4081.         formula := fFormula;
  4082.  
  4083.         WriteScrap(theScrap, scrapOffset, @cellInfo, cellLength);
  4084.         END;
  4085.     END;
  4086.  
  4087. {***************************************************************************************************
  4088.     T C a l c S e l e c t C o m m a n d
  4089. ***************************************************************************************************}
  4090. {$S ASelCommand}
  4091.  
  4092. PROCEDURE TCalcSelectCommand.ICalcSelectCommand(itsDocument: TCalcDocument;
  4093.                                                 itsView: TGridView;
  4094.                                                 theShiftKey, theCmdKey: BOOLEAN);
  4095.  
  4096.     BEGIN
  4097.     ICellSelectCommand(itsView, theShiftKey, theCmdKey);
  4098.     fCalcDocument := itsDocument;
  4099.     itsDocument.fEntryView.EditMode(FALSE);
  4100.     END;
  4101.  
  4102. {--------------------------------------------------------------------------------------------------}
  4103. {$S ADoCommand}
  4104.  
  4105. PROCEDURE TCalcSelectCommand.ComputeNewSelection(VAR clickedCell: GridCell); OVERRIDE;
  4106.  
  4107.     VAR
  4108.         r:                    Rect;
  4109.  
  4110.     BEGIN
  4111.     IF fGridView.CanSelectCell(clickedCell) THEN
  4112.         BEGIN
  4113.         Pt2Rect(fAnchorCell, clickedCell, r);
  4114.         r.right := r.right + 1;
  4115.         r.bottom := r.bottom + 1;
  4116.         RectRgn(fThisSelection, r);
  4117.         IF fCmdKey THEN
  4118.             IF fDeselecting THEN
  4119.                 DiffRgn(fPrevSelection, fThisSelection, fThisSelection)
  4120.             ELSE
  4121.                 UnionRgn(fPrevSelection, fThisSelection, fThisSelection);
  4122.         END;
  4123.     END;
  4124.  
  4125. {***************************************************************************************************
  4126.     T R o W S e l e c t o r
  4127. ***************************************************************************************************}
  4128. {$S ASelCommand}
  4129.  
  4130. PROCEDURE TRowSelector.IRowSelector(itsDocument: TCalcDocument;
  4131.                                     itsView: TGridView;
  4132.                                     theShiftKey, theCmdKey: BOOLEAN);
  4133.  
  4134.     VAR
  4135.         aCellSelector:        TCalcSelectCommand;
  4136.  
  4137.     BEGIN
  4138.     fCalcDocument := itsDocument;
  4139.     IF fCalcDocument.fSelectionType <> RowSelection THEN
  4140.         theCmdKey := FALSE;
  4141.     ICellSelectCommand(itsView, theShiftKey, theCmdKey);
  4142.  
  4143.     NEW(aCellSelector);
  4144.     FailNIL(aCellSelector);
  4145.     aCellSelector.ICalcSelectCommand(itsDocument, itsDocument.fCellsView, theShiftKey, theCmdKey);
  4146.     fCellSelector := aCellSelector;
  4147.     END;
  4148.  
  4149. {--------------------------------------------------------------------------------------------------}
  4150. {$S ARes}
  4151.  
  4152. PROCEDURE TRowSelector.Free; OVERRIDE;
  4153.  
  4154.     BEGIN
  4155.     FreeIfObject(fCellSelector);
  4156.     fCellSelector := NIL;
  4157.  
  4158.     INHERITED Free;
  4159.     END;
  4160.  
  4161. {--------------------------------------------------------------------------------------------------}
  4162. {$S ADoCommand}
  4163.  
  4164. PROCEDURE TRowSelector.ComputeAnchorCell(VAR clickedCell: GridCell); OVERRIDE;
  4165.  
  4166.     BEGIN
  4167.     INHERITED ComputeAnchorCell(clickedCell);
  4168.     fAnchorCell.h := 1;
  4169.  
  4170.     clickedCell.h := 1;
  4171.     fCellSelector.ComputeAnchorCell(clickedCell);
  4172.     END;
  4173.  
  4174. {--------------------------------------------------------------------------------------------------}
  4175. {$S ADoCommand}
  4176.  
  4177. PROCEDURE TRowSelector.ComputeNewSelection(VAR clickedCell: GridCell); OVERRIDE;
  4178.  
  4179.     VAR
  4180.         r:                    Rect;
  4181.  
  4182.     BEGIN
  4183.     clickedCell.h := fGridView.fNumOfCols;
  4184.     INHERITED ComputeNewSelection(clickedCell);
  4185.  
  4186.     clickedCell.h := fCalcDocument.fNoOfColumns;
  4187.     fCellSelector.ComputeNewSelection(clickedCell);
  4188.     END;
  4189.  
  4190. {--------------------------------------------------------------------------------------------------}
  4191. {$S ADoCommand}
  4192.  
  4193. PROCEDURE TRowSelector.DoIt; OVERRIDE;
  4194.  
  4195.     BEGIN
  4196.     INHERITED DoIt;
  4197.     fCellSelector.DoIt;
  4198.     END;
  4199.  
  4200. {--------------------------------------------------------------------------------------------------}
  4201. {$S ADoCommand}
  4202.  
  4203. FUNCTION TRowSelector.TrackMouse(aTrackPhase: TrackPhase;
  4204.                                  VAR anchorPoint, previousPoint, nextPoint: VPoint;
  4205.                                  mouseDidMove: BOOLEAN): TCommand; OVERRIDE;
  4206.  
  4207.     VAR
  4208.         clickedCell:        GridCell;
  4209.  
  4210.     BEGIN
  4211.     IF mouseDidMove THEN
  4212.         BEGIN
  4213.         clickedCell := fGridView.VPointToCell(nextPoint);
  4214.         IF aTrackPhase = TrackPress THEN
  4215.             BEGIN
  4216.             ComputeAnchorCell(clickedCell);
  4217.             IF fCmdKey THEN
  4218.                 BEGIN
  4219.                 fDeselecting := PtInRgn(fAnchorCell, fGridView.fSelections);
  4220.                 fCellSelector.fDeselecting := fDeselecting;
  4221.                 END;
  4222.             END;
  4223.  
  4224.         IF LONGINT(clickedCell) <> LONGINT(fPrevCell) THEN
  4225.             BEGIN
  4226.             ComputeNewSelection(clickedCell);
  4227.             HighlightNewSelection;
  4228.             fCellSelector.HighlightNewSelection;
  4229.  
  4230.             CopyRgn(fThisSelection, fPrevSelection);
  4231.             fPrevCell := clickedCell;
  4232.             WITH fCellSelector DO
  4233.                 BEGIN
  4234.                 CopyRgn(fThisSelection, fPrevSelection);
  4235.                 fPrevCell := clickedCell;
  4236.                 END;
  4237.             END;
  4238.         END;
  4239.     TrackMouse := SELF;
  4240.     END;
  4241.  
  4242. {***************************************************************************************************
  4243.     T C o l u m n S e l e c t o r
  4244. ***************************************************************************************************}
  4245. {$S ASelCommand}
  4246.  
  4247. PROCEDURE TColumnSelector.IColumnSelector(itsDocument: TCalcDocument;
  4248.                                           itsView: TGridView;
  4249.                                           theShiftKey, theCmdKey: BOOLEAN);
  4250.  
  4251.     VAR
  4252.         aCellSelector:        TCalcSelectCommand;
  4253.  
  4254.     BEGIN
  4255.     fCalcDocument := itsDocument;
  4256.     IF fCalcDocument.fSelectionType <> ColumnSelection THEN
  4257.         theCmdKey := FALSE;
  4258.     ICellSelectCommand(itsView, theShiftKey, theCmdKey);
  4259.  
  4260.     NEW(aCellSelector);
  4261.     FailNIL(aCellSelector);
  4262.     aCellSelector.ICalcSelectCommand(itsDocument, itsDocument.fCellsView, theShiftKey, theCmdKey);
  4263.     fCellSelector := aCellSelector;
  4264.     END;
  4265.  
  4266. {--------------------------------------------------------------------------------------------------}
  4267. {$S ARes}
  4268.  
  4269. PROCEDURE TColumnSelector.Free; OVERRIDE;
  4270.  
  4271.     BEGIN
  4272.     FreeIfObject(fCellSelector);
  4273.     fCellSelector := NIL;
  4274.  
  4275.     INHERITED Free;
  4276.     END;
  4277.  
  4278. {--------------------------------------------------------------------------------------------------}
  4279. {$S ADoCommand}
  4280.  
  4281. PROCEDURE TColumnSelector.ComputeAnchorCell(VAR clickedCell: GridCell); OVERRIDE;
  4282.  
  4283.     BEGIN
  4284.     INHERITED ComputeAnchorCell(clickedCell);
  4285.     fAnchorCell.v := 1;
  4286.  
  4287.     clickedCell.v := 1;
  4288.     fCellSelector.ComputeAnchorCell(clickedCell);
  4289.     END;
  4290.  
  4291. {--------------------------------------------------------------------------------------------------}
  4292. {$S ADoCommand}
  4293.  
  4294. PROCEDURE TColumnSelector.ComputeNewSelection(VAR clickedCell: GridCell); OVERRIDE;
  4295.  
  4296.     VAR
  4297.         r:                    Rect;
  4298.  
  4299.     BEGIN
  4300.     clickedCell.v := fGridView.fNumOfRows;
  4301.     INHERITED ComputeNewSelection(clickedCell);
  4302.  
  4303.     clickedCell.v := fCalcDocument.fNoOfRows;
  4304.     fCellSelector.ComputeNewSelection(clickedCell);
  4305.     END;
  4306.  
  4307. {--------------------------------------------------------------------------------------------------}
  4308. {$S ADoCommand}
  4309.  
  4310. PROCEDURE TColumnSelector.DoIt; OVERRIDE;
  4311.  
  4312.     BEGIN
  4313.     INHERITED DoIt;
  4314.     fCellSelector.DoIt;
  4315.     END;
  4316.  
  4317. {--------------------------------------------------------------------------------------------------}
  4318. {$S ADoCommand}
  4319.  
  4320. FUNCTION TColumnSelector.TrackMouse(aTrackPhase: TrackPhase;
  4321.                                     VAR anchorPoint, previousPoint, nextPoint: VPoint;
  4322.                                     mouseDidMove: BOOLEAN): TCommand; OVERRIDE;
  4323.  
  4324.     VAR
  4325.         clickedCell:        GridCell;
  4326.  
  4327.     BEGIN
  4328.     IF mouseDidMove THEN
  4329.         BEGIN
  4330.         clickedCell := fGridView.VPointToCell(nextPoint);
  4331.         IF aTrackPhase = TrackPress THEN
  4332.             BEGIN
  4333.             ComputeAnchorCell(clickedCell);
  4334.             IF fCmdKey THEN
  4335.                 BEGIN
  4336.                 fDeselecting := PtInRgn(fAnchorCell, fGridView.fSelections);
  4337.                 fCellSelector.fDeselecting := fDeselecting;
  4338.                 END;
  4339.             END;
  4340.  
  4341.         IF LONGINT(clickedCell) <> LONGINT(fPrevCell) THEN
  4342.             BEGIN
  4343.             ComputeNewSelection(clickedCell);
  4344.             HighlightNewSelection;
  4345.             fCellSelector.HighlightNewSelection;
  4346.  
  4347.             CopyRgn(fThisSelection, fPrevSelection);
  4348.             fPrevCell := clickedCell;
  4349.             WITH fCellSelector DO
  4350.                 BEGIN
  4351.                 CopyRgn(fThisSelection, fPrevSelection);
  4352.                 fPrevCell := clickedCell;
  4353.                 END;
  4354.             END;
  4355.         END;
  4356.     TrackMouse := SELF;
  4357.     END;
  4358.  
  4359. {***************************************************************************************************
  4360.     T C o l u m n F o r m a t t e r
  4361. ***************************************************************************************************}
  4362. {$S ASelCommand}
  4363.  
  4364. PROCEDURE TColumnFormatter.IFormatter(itsDocument: TCalcDocument;
  4365.                                       itsCommand: INTEGER);
  4366.  
  4367. {--------------------------------------------------------------------------------------------------}
  4368.  
  4369.     PROCEDURE SaveFormat(aCell: GridCell);
  4370.  
  4371.         VAR
  4372.             theColumn:            TColumn;
  4373.  
  4374.         BEGIN
  4375.         theColumn := fCalcDocument.GetColumn(aCell.h);
  4376.         theColumn.fOldFormat := theColumn.fFormat;
  4377.         END;
  4378.  
  4379.     BEGIN
  4380.     ICommand(itsCommand, itsDocument, itsDocument.fCellsView,
  4381.              itsDocument.fColumnsView.GetScroller(TRUE));
  4382.     fCalcDocument := itsDocument;
  4383.     fSelection := MakeNewRgn;                            { copy the current selection region }
  4384.     CopyRgn(itsDocument.fColumnsView.fSelections, fSelection);
  4385.     fCalcDocument.fColumnsView.EachSelectedCellDo(SaveFormat);
  4386.     END;
  4387.  
  4388. {--------------------------------------------------------------------------------------------------}
  4389. {$S ADoCommand}
  4390.  
  4391. PROCEDURE TColumnFormatter.DoIt; OVERRIDE;
  4392.  
  4393.     PROCEDURE SetFormat(aCell: GridCell);
  4394.  
  4395.         VAR
  4396.             theColumn:            TColumn;
  4397.  
  4398.         BEGIN
  4399.         theColumn := fCalcDocument.GetColumn(aCell.h);
  4400.         WITH theColumn.fFormat DO
  4401.             CASE fCmdNumber OF
  4402.                 cGeneral:
  4403.                     fStyle := General;
  4404.                 cNoDecimal:
  4405.                     fStyle := NoDecimal;
  4406.                 cDecimal:
  4407.                     fStyle := DecimalStyle;
  4408.                 cScientific:
  4409.                     fStyle := Scientific;
  4410.                 cSystemJustify:
  4411.                     fJustification := teJustSystem;
  4412.                 cForceLeftJustify:
  4413.                     fJustification := teForceLeft;
  4414.                 cRightJustify:
  4415.                     fJustification := TEJustRight;
  4416.                 cCenter:
  4417.                     fJustification := TEJustCenter;
  4418.             END;
  4419.         END;
  4420.  
  4421.     BEGIN
  4422.     fCalcDocument.fColumnsView.EachSelectedCellDo(SetFormat);
  4423.     IF (fCmdNumber >= cGeneral) & (fCmdNumber <= cScientific) THEN { Style change }
  4424.         fCalcDocument.DoRecalculate(NOT kForceAutomatic, NOT kSetDependents);
  4425.     fCalcDocument.fCellsView.InvalidateSelection;
  4426.     END;
  4427.  
  4428. {--------------------------------------------------------------------------------------------------}
  4429. {$S ADoCommand}
  4430.  
  4431. PROCEDURE TColumnFormatter.Free; OVERRIDE;
  4432.  
  4433.     BEGIN
  4434.     IF fSelection <> NIL THEN
  4435.         DisposeRgn(fSelection);
  4436.     fSelection := NIL;
  4437.  
  4438.     INHERITED Free;
  4439.     END;
  4440.  
  4441. {--------------------------------------------------------------------------------------------------}
  4442. {$S ADoCommand}
  4443.  
  4444. PROCEDURE TColumnFormatter.RedoIt; OVERRIDE;
  4445.  
  4446.     BEGIN
  4447.     fCalcDocument.fColumnsView.ReSelect(fSelection);
  4448.     DoIt;
  4449.     END;
  4450.  
  4451. {--------------------------------------------------------------------------------------------------}
  4452. {$S ADoCommand}
  4453.  
  4454. PROCEDURE TColumnFormatter.UndoIt; OVERRIDE;
  4455.  
  4456.     PROCEDURE RestoreFormat(aCell: GridCell);
  4457.  
  4458.         VAR
  4459.             theColumn:            TColumn;
  4460.  
  4461.         BEGIN
  4462.         theColumn := fCalcDocument.GetColumn(aCell.h);
  4463.         theColumn.fFormat := theColumn.fOldFormat;
  4464.         END;
  4465.  
  4466.     BEGIN
  4467.     WITH fCalcDocument.fColumnsView DO
  4468.         BEGIN
  4469.         ReSelect(fSelection);
  4470.         EachSelectedCellDo(RestoreFormat);
  4471.         END;
  4472.     IF (fCmdNumber >= cGeneral) & (fCmdNumber <= cScientific) THEN { Style change }
  4473.         fCalcDocument.DoRecalculate(NOT kForceAutomatic, NOT kSetDependents);
  4474.     fCalcDocument.fCellsView.InvalidateSelection;
  4475.     END;
  4476.  
  4477. {--------------------------------------------------------------------------------------------------}
  4478. {$S AFields}
  4479.  
  4480. PROCEDURE TColumnFormatter.Fields(PROCEDURE DoToField(fieldName: Str255;
  4481.                                                       fieldAddr: Ptr;
  4482.                                                       fieldType: INTEGER)); OVERRIDE;
  4483.  
  4484.     BEGIN
  4485.     DoToField('TColumnFormatter', NIL, bClass);
  4486.     DoToField('fCalcDocument', @fCalcDocument, bObject);
  4487.     INHERITED Fields(DoToField);
  4488.     END;
  4489.  
  4490. {***************************************************************************************************
  4491.     T C o l u m n S i z e r
  4492. ***************************************************************************************************}
  4493. {$S ASelCommand}
  4494.  
  4495. PROCEDURE TColumnSizer.IColumnSizer(itsDocument: TCalcDocument;
  4496.                                     c: ColumnNumber);
  4497.  
  4498.     VAR
  4499.         colRect:            VRect;
  4500.  
  4501.     BEGIN
  4502.     ICommand(cSizeColumn, itsDocument, itsDocument.fCellsView,
  4503.              itsDocument.fColumnsView.GetScroller(TRUE));
  4504.     fConstrainsMouse := TRUE;
  4505.     fCalcDocument := itsDocument;
  4506.     fCellsView := itsDocument.fCellsView;
  4507.     fColumn := itsDocument.GetColumn(c);
  4508.     fNewWidth := fCellsView.GetColWidth(fColumn.fNumber);
  4509.     fOldWidth := fNewWidth;
  4510.     fCellsView.ColToVRect(fColumn.fNumber, 1, colRect);
  4511.     fLeftEdge := colRect.left;
  4512.     fViewConstrain := FALSE;                            { So that rightmost column can grow }
  4513.     END;
  4514.  
  4515. {--------------------------------------------------------------------------------------------------}
  4516. {$S ADoCommand}
  4517.  
  4518. FUNCTION TColumnSizer.TrackMouse(aTrackPhase: TrackPhase;
  4519.                                  VAR anchorPoint, previousPoint, nextPoint: VPoint;
  4520.                                  mouseDidMove: BOOLEAN): TCommand; OVERRIDE;
  4521.  
  4522.     BEGIN
  4523.     fNewWidth := Min(nextPoint.h - fLeftEdge, kTELength);
  4524.     fNewWidth := Max(fNewWidth, 10);
  4525.     TrackMouse := SELF;
  4526.     nextPoint.h := Min(nextPoint.h, fLeftEdge + kTELength);
  4527.     END;
  4528.  
  4529. {--------------------------------------------------------------------------------------------------}
  4530. {$S ADoCommand}
  4531.  
  4532. PROCEDURE TColumnSizer.TrackFeedback(anchorPoint, nextPoint: VPoint;
  4533.                                      turnItOn, mouseDidMove: BOOLEAN); OVERRIDE;
  4534.  
  4535.     VAR
  4536.         viewedRect:         Rect;
  4537.         pState:             PenState;
  4538.  
  4539.     BEGIN
  4540.     IF mouseDidMove THEN
  4541.         BEGIN
  4542.         GetPenState(pState);
  4543.         PenPat(black);
  4544.  
  4545.         fCellsView.GetQDExtent(viewedRect);
  4546.  
  4547.         MoveTo(Min(nextPoint.h, fLeftEdge + kTELength), viewedRect.top);
  4548.         Line(0, viewedRect.bottom - viewedRect.top);
  4549.         SetPenState(pState);
  4550.         END;
  4551.     END;
  4552.  
  4553. {--------------------------------------------------------------------------------------------------}
  4554. {$S ADoCommand}
  4555.  
  4556. PROCEDURE TColumnSizer.TrackConstrain(anchorPoint, previousPoint: VPoint;
  4557.                                       VAR nextPoint: VPoint); OVERRIDE;
  4558.  
  4559.     BEGIN
  4560.     IF nextPoint.h < fLeftEdge + 10 THEN
  4561.         nextPoint.h := fLeftEdge + 10
  4562.     ELSE
  4563.         nextPoint.h := Min(nextPoint.h, fLeftEdge + kTELength);
  4564.     END;
  4565.  
  4566. {--------------------------------------------------------------------------------------------------}
  4567. {$S ADoCommand}
  4568.  
  4569. PROCEDURE TColumnSizer.SetColumnWidth(newWidth: INTEGER);
  4570.  
  4571.     BEGIN
  4572.     IF newWidth > kTELength THEN
  4573.         BEGIN
  4574.         newWidth := kTELength;
  4575.         fNewWidth := kTELength;
  4576.         END
  4577.     ELSE IF newWidth < 10 THEN
  4578.         newWidth := 10;
  4579.  
  4580.     fCellsView.SetColWidth(fColumn.fNumber, 1, newWidth);
  4581.     fCalcDocument.fColumnsView.SetColWidth(fColumn.fNumber, 1, newWidth);
  4582.     fColumn.fWidth := newWidth;
  4583.     END;
  4584.  
  4585. {--------------------------------------------------------------------------------------------------}
  4586. {$S ADoCommand}
  4587.  
  4588. PROCEDURE TColumnSizer.DoIt; OVERRIDE;
  4589.  
  4590.     VAR
  4591.         minToSee:            Point;
  4592.         aRect:                VRect;
  4593.  
  4594.     BEGIN
  4595.     SetColumnWidth(fNewWidth);
  4596.  
  4597.     fCellsView.ColToVRect(fColumn.fNumber, 1, aRect);
  4598.     WITH aRect DO
  4599.         SetPt(minToSee, right - left, bottom - top);
  4600.     fCellsView.RevealRect(aRect, minToSee, TRUE);
  4601.  
  4602.     fCalcDocument.fColumnsView.ColToVRect(fColumn.fNumber, 1, aRect);
  4603.     WITH aRect DO
  4604.         SetPt(minToSee, right - left, bottom - top);
  4605.     fCalcDocument.fColumnsView.RevealRect(aRect, minToSee, TRUE);
  4606.     END;
  4607.  
  4608. {--------------------------------------------------------------------------------------------------}
  4609. {$S ADoCommand}
  4610.  
  4611. PROCEDURE TColumnSizer.UndoIt; OVERRIDE;
  4612.  
  4613.     BEGIN
  4614.     SetColumnWidth(fOldWidth);
  4615.     END;
  4616.  
  4617. {--------------------------------------------------------------------------------------------------}
  4618. {$S ADoCommand}
  4619.  
  4620. PROCEDURE TColumnSizer.RedoIt; OVERRIDE;
  4621.  
  4622.     BEGIN
  4623.     DoIt;
  4624.     END;
  4625.  
  4626. {--------------------------------------------------------------------------------------------------}
  4627. {$S AFields}
  4628.  
  4629. PROCEDURE TColumnSizer.Fields(PROCEDURE DoToField(fieldName: Str255;
  4630.                                                   fieldAddr: Ptr;
  4631.                                                   fieldType: INTEGER)); OVERRIDE;
  4632.  
  4633.     BEGIN
  4634.     DoToField('TColumnSizer', NIL, bClass);
  4635.     DoToField('fCalcDocument', @fCalcDocument, bObject);
  4636.     DoToField('fCellsView', @fCellsView, bObject);
  4637.     DoToField('fLeftEdge', @fLeftEdge, bInteger);
  4638.     DoToField('fColumn', @fColumn, bObject);
  4639.     DoToField('fNewWidth', @fNewWidth, bInteger);
  4640.     DoToField('fOldWidth', @fOldWidth, bInteger);
  4641.     INHERITED Fields(DoToField);
  4642.     END;
  4643.  
  4644. {***************************************************************************************************
  4645.     T C a l c T y p i n g C o m m a n d
  4646. ***************************************************************************************************}
  4647. {$S ADoCommand}
  4648.  
  4649. PROCEDURE TCalcTypingCommand.ITETypingCommand(itsTEView: TTEView;
  4650.                                               itsFirstChar: CHAR); OVERRIDE;
  4651.  
  4652.     BEGIN
  4653.     fCellsView := TEntryView(itsTEView).fCalcDocument.fCellsView;
  4654.     fTargetCell := fCellsView.FirstSelectedCell;
  4655.     INHERITED ITETypingCommand(itsTEView, itsFirstChar);
  4656.     END;
  4657.  
  4658. {--------------------------------------------------------------------------------------------------}
  4659. {$S ARes}
  4660.  
  4661. PROCEDURE TCalcTypingCommand.AddCharacter(aChar: CHAR); OVERRIDE;
  4662. { Switch the entry view from left to right justification when the typed characters overflow the
  4663.   entry box, and switch back to left justification if the text shrinks enough }
  4664.  
  4665.     VAR
  4666.         selRight:            INTEGER;
  4667.  
  4668. {--------------------------------------------------------------------------------------------------}
  4669.  
  4670.     FUNCTION AddCharWidths: INTEGER;
  4671.  
  4672.         VAR
  4673.             aString:            Str255;
  4674.  
  4675.         BEGIN
  4676.         GetIText(fHTE^^.hText, aString);
  4677.         AddCharWidths := StringWidth(aString);
  4678.         END;
  4679.  
  4680.     BEGIN
  4681.     IF (aChar <> chBackspace) & (fTEView.fJustification = TEJustLeft) THEN
  4682.         BEGIN
  4683.         selRight := fHTE^^.selRect.right;
  4684.         IF (selRight < 0) | (selRight > fHTE^^.destRect.right) THEN
  4685.             selRight := fHTE^^.selPoint.h;
  4686.         IF selRight + CharWidth(aChar) > fHTE^^.destRect.right THEN
  4687.             fTEView.SetJustification(TEJustRight, kDontRedraw);
  4688.         END;
  4689.  
  4690.     INHERITED AddCharacter(aChar);
  4691.  
  4692.     IF (aChar = chBackspace) & (fTEView.fJustification = TEJustRight) THEN
  4693.         IF AddCharWidths < LengthRect(fHTE^^.destRect, h) THEN
  4694.             fTEView.SetJustification(TEJustLeft, kRedraw);
  4695.     END;
  4696.  
  4697. {--------------------------------------------------------------------------------------------------}
  4698. {$S ADoCommand}
  4699.  
  4700. PROCEDURE TCalcTypingCommand.UndoIt; OVERRIDE;
  4701. { If the selection has changed since this command was created, restore it to the
  4702.   target cell before Undoing. }
  4703.  
  4704.     VAR
  4705.         entryView:            TEntryView;
  4706.  
  4707.     BEGIN
  4708.     fCellsView.ReSelectCell(fTargetCell);                { make sure fTargetCell is selected }
  4709.     entryView := TEntryView(fTEView);
  4710.     IF (entryView.fTEditing) & (NOT entryView.fFirstEdit) THEN
  4711.         INHERITED UndoIt                                { TTE undo }
  4712.     ELSE
  4713.         BEGIN
  4714.         entryView.SwapStrings;                            { exchange current and saved strings }
  4715.         fCellsView.SetCell(fTargetCell);                { change fTargetCell's contents and redraw
  4716.                                                          it }
  4717.         END;
  4718.     END;
  4719.  
  4720. {--------------------------------------------------------------------------------------------------}
  4721. {$S ADoCommand}
  4722.  
  4723. PROCEDURE TCalcTypingCommand.RedoIt; OVERRIDE;
  4724. { If the selection has changed since this command was created, restore it to the
  4725.   target cell before Redoing. }
  4726.  
  4727.     VAR
  4728.         entryView:            TEntryView;
  4729.  
  4730.     BEGIN
  4731.     fCellsView.ReSelectCell(fTargetCell);                { make sure fTargetCell is selected }
  4732.     entryView := TEntryView(fTEView);
  4733.     IF (entryView.fTEditing) & (NOT entryView.fFirstEdit) THEN
  4734.         INHERITED RedoIt                                { TTE redo }
  4735.     ELSE
  4736.         BEGIN
  4737.         entryView.SwapStrings;                            { exchange current and saved strings }
  4738.         fCellsView.SetCell(fTargetCell);                { change fTargetCell's contents and redraw
  4739.                                                          it }
  4740.         END;
  4741.     END;
  4742.  
  4743. {--------------------------------------------------------------------------------------------------}
  4744. {$S AFields}
  4745.  
  4746. PROCEDURE TCalcTypingCommand.Fields(PROCEDURE DoToField(fieldName: Str255;
  4747.                                                         fieldAddr: Ptr;
  4748.                                                         fieldType: INTEGER)); OVERRIDE;
  4749.  
  4750.     BEGIN
  4751.     DoToField('TCalcTypingCommand', NIL, bClass);
  4752.     DoToField('fCellsView', @fCellsView, bObject);
  4753.     DoToField('fTargetCell', @fTargetCell, bPoint);
  4754.     INHERITED Fields(DoToField);
  4755.     END;
  4756.  
  4757. {***************************************************************************************************
  4758.     T C e l l E d i t C o m m a n d
  4759. ***************************************************************************************************}
  4760. {$S ASelCommand}
  4761.  
  4762. PROCEDURE TCellEditCommand.ICellEditCommand(itsDocument: TCalcDocument;
  4763.                                             itsCommand: INTEGER);
  4764.  
  4765.     BEGIN
  4766.     ICommand(itsCommand, itsDocument, itsDocument.fCellsView, NIL);
  4767.     fCalcDocument := itsDocument;
  4768.     fSelection := MakeNewRgn;                            { copy the current selection region }
  4769.     CopyRgn(itsDocument.fCellsView.fSelections, fSelection);
  4770.     fChangesClipboard := itsCommand <> cClear;
  4771.     fCausesChange := itsCommand <> cCopy;
  4772.     END;
  4773.  
  4774. {--------------------------------------------------------------------------------------------------}
  4775. {$S ARes}
  4776.  
  4777. PROCEDURE TCellEditCommand.Free; OVERRIDE;
  4778.  
  4779.     BEGIN
  4780.     IF fSelection <> NIL THEN
  4781.         DisposeRgn(fSelection);
  4782.     fSelection := NIL;
  4783.  
  4784.     INHERITED Free;
  4785.     END;
  4786.  
  4787. {--------------------------------------------------------------------------------------------------}
  4788. {$S ADoCommand}
  4789.  
  4790. PROCEDURE TCellEditCommand.CopySelection;
  4791.  
  4792.     VAR
  4793.         clipDocument:        TCalcDocument;
  4794.         clipView:            TCellsView;
  4795.         clipRect:            Rect;
  4796.  
  4797. {--------------------------------------------------------------------------------------------------}
  4798.  
  4799.     PROCEDURE CopyRowToClipboard(aCell: GridCell);
  4800.  
  4801.         VAR
  4802.             newRow:             TRow;
  4803.  
  4804.         BEGIN
  4805.         newRow := TRow(fCalcDocument.GetRow(aCell.v).Clone);
  4806.         newRow.fNumber := newRow.fNumber - clipDocument.fRowOffset;
  4807.         clipDocument.AddRow(newRow);
  4808.         END;
  4809.  
  4810. {--------------------------------------------------------------------------------------------------}
  4811.  
  4812.     PROCEDURE CopyColumnToClipboard(aCell: GridCell);
  4813.  
  4814.         VAR
  4815.             newColumn:            TColumn;
  4816.  
  4817.         BEGIN
  4818.         newColumn := TColumn(fCalcDocument.GetColumn(aCell.h).Clone);
  4819.         newColumn.fNumber := newColumn.fNumber - clipDocument.fColumnOffset;
  4820.         clipDocument.AddColumn(newColumn);
  4821.         END;
  4822.  
  4823. {--------------------------------------------------------------------------------------------------}
  4824.  
  4825.     PROCEDURE CopyCellToClipboard(aCell: GridCell);
  4826.  
  4827.         VAR
  4828.             newCell:            TCell;
  4829.             oldCell:            TCell;
  4830.  
  4831.         BEGIN
  4832.         oldCell := fCalcDocument.GetExistingCell(aCell.v, aCell.h);
  4833.         IF oldCell <> NIL THEN
  4834.             BEGIN
  4835.             newCell := TCell(oldCell.Clone);
  4836.             clipDocument.AddCell(newCell, newCell.fRow - clipDocument.fRowOffset, newCell.fColumn -
  4837.                                  clipDocument.fColumnOffset);
  4838.             END;
  4839.         END;
  4840.  
  4841.     BEGIN
  4842.     NEW(clipDocument);
  4843.     FailNIL(clipDocument);
  4844.     clipRect := fSelection^^.rgnBBox;
  4845.     clipRect.bottom := clipRect.bottom - 1;
  4846.     clipRect.right := clipRect.right - 1;
  4847.     clipDocument.ICalcDocument(clipRect);
  4848.     clipDocument.DoInitialState;
  4849.  
  4850.     fCalcDocument.fRowsView.EachSelectedCellDo(CopyRowToClipboard);
  4851.     fCalcDocument.fColumnsView.EachSelectedCellDo(CopyColumnToClipboard);
  4852.     fCalcDocument.fCellsView.EachSelectedCellDo(CopyCellToClipboard);
  4853.  
  4854.     NEW(clipView);
  4855.     FailNIL(clipView);
  4856.     clipView.ICellsView(clipDocument, TRUE, NIL);
  4857.     clipDocument.fCellsView := clipView;
  4858.     gApplication.ClaimClipboard(clipView);
  4859.     clipView.AdjustSize;
  4860.     END;
  4861.  
  4862. {--------------------------------------------------------------------------------------------------}
  4863. {$S ADoCommand}
  4864.  
  4865. PROCEDURE TCellEditCommand.DeleteSelection;
  4866.  
  4867. {--------------------------------------------------------------------------------------------------}
  4868.  
  4869.     PROCEDURE DeleteCell(aCell: GridCell);
  4870.  
  4871.         BEGIN
  4872.         fCalcDocument.DeleteCell(aCell.v, aCell.h);
  4873.         END;
  4874.  
  4875.     BEGIN
  4876.     fCalcDocument.fCellsView.EachSelectedCellDo(DeleteCell);
  4877.     fCalcDocument.DoRecalculate(NOT kForceAutomatic, NOT kSetDependents);
  4878.     fCalcDocument.fCellsView.InvalidateSelection;
  4879.     END;
  4880.  
  4881. {--------------------------------------------------------------------------------------------------}
  4882. {$S ADoCommand}
  4883.  
  4884. PROCEDURE TCellEditCommand.RestoreSelection;
  4885.  
  4886.     VAR
  4887.         firstCell:            GridCell;
  4888.  
  4889. {--------------------------------------------------------------------------------------------------}
  4890.  
  4891.     PROCEDURE RestoreCell(aCell: GridCell);
  4892.  
  4893.         BEGIN
  4894.         fCalcDocument.UndeleteCell(aCell.v, aCell.h);
  4895.         END;
  4896.  
  4897.     BEGIN
  4898.     fCalcDocument.fCellsView.EachSelectedCellDo(RestoreCell);
  4899.     fCalcDocument.DoRecalculate(NOT kForceAutomatic, NOT kSetDependents);
  4900.     fCalcDocument.fCellsView.InvalidateSelection;
  4901.  
  4902.     firstCell := fCalcDocument.fCellsView.FirstSelectedCell;
  4903.     fCalcDocument.SetEntry(firstCell.v, firstCell.h);    { update entry view }
  4904.     END;
  4905.  
  4906. {--------------------------------------------------------------------------------------------------}
  4907. {$S ADoCommand}
  4908.  
  4909. PROCEDURE TCellEditCommand.ReSelect;
  4910.  
  4911.     BEGIN
  4912.     fCalcDocument.fCellsView.ReSelect(fSelection);
  4913.     END;
  4914.  
  4915. {--------------------------------------------------------------------------------------------------}
  4916. {$S ADoCommand}
  4917.  
  4918. PROCEDURE TCellEditCommand.DoIt;
  4919.  
  4920.     BEGIN
  4921.     IF fCmdNumber <> cClear THEN
  4922.         CopySelection;
  4923.     IF fCmdNumber <> cCopy THEN
  4924.         DeleteSelection;
  4925.     END;
  4926.  
  4927. {--------------------------------------------------------------------------------------------------}
  4928. {$S ADoCommand}
  4929.  
  4930. PROCEDURE TCellEditCommand.UndoIt;
  4931. { If the user has changed the selection since this command was created,
  4932.   restore it before Undoing so that the correct cells are affected. }
  4933.  
  4934.     BEGIN
  4935.     IF fCmdNumber <> cCopy THEN
  4936.         BEGIN
  4937.         ReSelect;                                        { restore command's original selection }
  4938.         RestoreSelection;
  4939.         fCalcDocument.fCellsView.ScrollSelectionIntoView(TRUE);
  4940.         END;
  4941.     END;
  4942.  
  4943. {--------------------------------------------------------------------------------------------------}
  4944. {$S ADoCommand}
  4945.  
  4946. PROCEDURE TCellEditCommand.RedoIt;
  4947. { If the user has changed the selection since this command was created,
  4948.   restore it before Redoing so that the correct cells are affected. }
  4949.  
  4950.     BEGIN
  4951.     IF fCmdNumber <> cCopy THEN
  4952.         BEGIN
  4953.         ReSelect;                                        { restore command's original selection }
  4954.         DeleteSelection;
  4955.         fCalcDocument.fCellsView.ScrollSelectionIntoView(TRUE);
  4956.         END;
  4957.     END;
  4958.  
  4959. {--------------------------------------------------------------------------------------------------}
  4960. {$S ADoCommand}
  4961.  
  4962. PROCEDURE TCellEditCommand.Commit;
  4963.  
  4964.     BEGIN
  4965.     fCalcDocument.FreeDeletedCells;
  4966.     END;
  4967.  
  4968. {--------------------------------------------------------------------------------------------------}
  4969. {$S AFields}
  4970.  
  4971. PROCEDURE TCellEditCommand.Fields(PROCEDURE DoToField(fieldName: Str255;
  4972.                                                       fieldAddr: Ptr;
  4973.                                                       fieldType: INTEGER)); OVERRIDE;
  4974.  
  4975.     BEGIN
  4976.     DoToField('TCellEditCommand', NIL, bClass);
  4977.     DoToField('fCalcDocument', @fCalcDocument, bObject);
  4978.     DoToField('fSelection', @fSelection, bRgnHandle);
  4979.     INHERITED Fields(DoToField);
  4980.     END;
  4981.  
  4982. {***************************************************************************************************
  4983.     T C e l l P a s t e C o m m a n d
  4984. ***************************************************************************************************}
  4985. {$S ASelCommand}
  4986.  
  4987. PROCEDURE TCellPasteCommand.ICellPasteCommand(itsDocument: TCalcDocument);
  4988.  
  4989.     BEGIN
  4990.     {$IFC qDebug}
  4991.     IF NOT Member(gClipView, TCellsView) THEN
  4992.         ProgramBreak('Attempt to paste a non-TCellsView clipboard');
  4993.     {$ENDC}
  4994.     ICommand(cPaste, itsDocument, itsDocument.fCellsView, NIL);
  4995.     fCalcDocument := itsDocument;
  4996.     fSelection := MakeNewRgn;                            { copy the current selection region }
  4997.     CopyRgn(itsDocument.fCellsView.fSelections, fSelection);
  4998.     fClipDocument := TCellsView(gClipView).fCalcDocument;
  4999.     fReplacedCells := NewList;
  5000.     FailNIL(fReplacedCells);
  5001.     {$IFC qDebug}
  5002.     fReplacedCells.SetEltType('TCell');
  5003.     {$ENDC}
  5004.     END;
  5005.  
  5006. {--------------------------------------------------------------------------------------------------}
  5007. {$S ADoCommand}
  5008.  
  5009. PROCEDURE TCellPasteCommand.Free; OVERRIDE;
  5010.  
  5011.     BEGIN
  5012.     IF fSelection <> NIL THEN
  5013.         DisposeRgn(fSelection);
  5014.     fSelection := NIL;
  5015.  
  5016.     fReplacedCells := FreeListIfObject(fReplacedCells);
  5017.  
  5018.     INHERITED Free;
  5019.     END;
  5020.  
  5021. {--------------------------------------------------------------------------------------------------}
  5022. {$S ADoCommand}
  5023.  
  5024. PROCEDURE TCellPasteCommand.DoIt;
  5025.  
  5026.     VAR
  5027.         r:                    INTEGER;                    { Can't use RowNumber or ColumnNumber }
  5028.         c:                    INTEGER;                    { … because they may be out of range }
  5029.         fi:                 FailInfo;
  5030.  
  5031. {--------------------------------------------------------------------------------------------------}
  5032.  
  5033.     PROCEDURE PasteCell(aCell: GridCell);
  5034.  
  5035.         VAR
  5036.             sourceCell:         TCell;
  5037.             replacedCell:        TCell;
  5038.             destCell:            TCell;
  5039.  
  5040.         BEGIN
  5041.         destCell := fCalcDocument.GetCell(aCell.v, aCell.h);
  5042.         replacedCell := TCell(destCell.Clone);
  5043.         fReplacedCells.InsertLast(replacedCell);
  5044.  
  5045.         sourceCell := fClipDocument.GetCell(r, c);
  5046.         c := c + 1;
  5047.         IF c > fClipDocument.fNoOfColumns THEN
  5048.             BEGIN
  5049.             c := 1;
  5050.             r := r + 1;
  5051.             IF r > fClipDocument.fNoOfRows THEN
  5052.                 r := 1;
  5053.             END;
  5054.  
  5055.         destCell.CopyContents(sourceCell);                { copy the necessary fields }
  5056.         END;
  5057.  
  5058. {--------------------------------------------------------------------------------------------------}
  5059.  
  5060.     PROCEDURE HdlPasteFailure(error: OSErr;
  5061.                               message: LONGINT);
  5062.     { We ran out of memory and couldn't complete the paste.
  5063.       So, let's back out the partial paste. All or nothing! }
  5064.  
  5065. {--------------------------------------------------------------------------------------------------}
  5066.  
  5067.         PROCEDURE RestoreCell(replacedCell: TCell);
  5068.  
  5069.             VAR
  5070.                 pastedCell:         TCell;
  5071.  
  5072.             BEGIN
  5073.             pastedCell := fCalcDocument.GetCell(replacedCell.fRow, replacedCell.fColumn);
  5074.             IF replacedCell.IsEmpty THEN                { free up memory used by empty cell }
  5075.                 BEGIN
  5076.                 fCalcDocument.DeleteCell(pastedCell.fRow, pastedCell.fColumn);
  5077.                 fCalcDocument.FreeCell(pastedCell);
  5078.                 END
  5079.             ELSE
  5080.                 pastedCell.CopyContents(replacedCell);
  5081.             FreeIfObject(replacedCell);                            { free up memory used by replacement cell }
  5082.             replacedCell := NIL;
  5083.             END;
  5084.  
  5085.         BEGIN
  5086.         fReplacedCells.Each(RestoreCell);
  5087.         fReplacedCells.DeleteAll;
  5088.         UpdateViews;
  5089.         END;
  5090.  
  5091.     BEGIN                                                { TCellPasteCommand.DoIt }
  5092.     CatchFailures(fi, HdlPasteFailure);
  5093.     r := 1;
  5094.     c := 1;
  5095.     fCalcDocument.fCellsView.EachSelectedCellDo(PasteCell);
  5096.     Success(fi);
  5097.     UpdateViews;
  5098.     END;
  5099.  
  5100. {--------------------------------------------------------------------------------------------------}
  5101. {$S ADoCommand}
  5102.  
  5103. PROCEDURE TCellPasteCommand.UndoIt;
  5104.  
  5105. {--------------------------------------------------------------------------------------------------}
  5106.  
  5107.     PROCEDURE RestoreCell(replacedCell: TCell);
  5108.  
  5109.         VAR
  5110.             pastedCell:         TCell;
  5111.  
  5112.         BEGIN
  5113.         pastedCell := fCalcDocument.GetCell(replacedCell.fRow, replacedCell.fColumn);
  5114.         pastedCell.CopyContents(replacedCell);
  5115.         END;
  5116.  
  5117.     BEGIN
  5118.     fCalcDocument.fCellsView.ReSelect(fSelection);        { restore original selection }
  5119.     fReplacedCells.Each(RestoreCell);
  5120.     UpdateViews;
  5121.     END;
  5122.  
  5123. {--------------------------------------------------------------------------------------------------}
  5124. {$S ADoCommand}
  5125.  
  5126. PROCEDURE TCellPasteCommand.RedoIt;
  5127.  
  5128.     VAR
  5129.         r:                    INTEGER;                    { Can't use RowNumber or ColumnNumber }
  5130.         c:                    INTEGER;                    { … because they may be out of range }
  5131.  
  5132. {--------------------------------------------------------------------------------------------------}
  5133.  
  5134.     PROCEDURE RepasteCell(aCell: GridCell);
  5135.  
  5136.         VAR
  5137.             sourceCell:         TCell;
  5138.             destCell:            TCell;
  5139.  
  5140.         BEGIN
  5141.         destCell := fCalcDocument.GetCell(aCell.v, aCell.h);
  5142.         sourceCell := fClipDocument.GetCell(r, c);
  5143.         c := c + 1;
  5144.         IF c > fClipDocument.fNoOfColumns THEN
  5145.             BEGIN
  5146.             c := 1;
  5147.             r := r + 1;
  5148.             IF r > fClipDocument.fNoOfRows THEN
  5149.                 r := 1;
  5150.             END;
  5151.  
  5152.         destCell.CopyContents(sourceCell);
  5153.         END;
  5154.  
  5155.     BEGIN
  5156.     fCalcDocument.fCellsView.ReSelect(fSelection);        { restore original selection }
  5157.     r := 1;
  5158.     c := 1;
  5159.     fCalcDocument.fCellsView.EachSelectedCellDo(RepasteCell);
  5160.     UpdateViews;
  5161.     END;
  5162.  
  5163. {--------------------------------------------------------------------------------------------------}
  5164. {$S ADoCommand}
  5165.  
  5166. PROCEDURE TCellPasteCommand.UpdateViews;
  5167.  
  5168.     VAR
  5169.         aString:            Str255;
  5170.         aCell:                GridCell;
  5171.  
  5172.     BEGIN
  5173.     WITH fCalcDocument DO
  5174.         BEGIN
  5175.         DoRecalculate(NOT kForceAutomatic, kSetDependents);
  5176.         fCellsView.InvalidateSelection;
  5177.  
  5178.         aCell.h := fEditColumn;
  5179.         aCell.v := fEditRow;
  5180.         IF fCellsView.IsCellSelected(aCell) THEN
  5181.             BEGIN
  5182.             fEditCell := GetCell(aCell.v, aCell.h);
  5183.             fEditCell.GetAsString(aString);
  5184.             fEntryView.SetToString(aString);
  5185.             END;
  5186.         END;
  5187.     END;
  5188.  
  5189. {--------------------------------------------------------------------------------------------------}
  5190. {$S AFields}
  5191.  
  5192. PROCEDURE TCellPasteCommand.Fields(PROCEDURE DoToField(fieldName: Str255;
  5193.                                                        fieldAddr: Ptr;
  5194.                                                        fieldType: INTEGER)); OVERRIDE;
  5195.  
  5196.     BEGIN
  5197.     DoToField('TCellPasteCommand', NIL, bClass);
  5198.     DoToField('fClipDocument', @fClipDocument, bObject);
  5199.     DoToField('fCalcDocument', @fCalcDocument, bObject);
  5200.     DoToField('fSelection', @fSelection, bRgnHandle);
  5201.     DoToField('fReplacedCells', @fReplacedCells, bObject);
  5202.     INHERITED Fields(DoToField);
  5203.     END;
  5204.